bind/java: reenable asset access.
This is done by moving app.Context to internal/mobileinit, introducing mobileinit.SetCurrentContext and, making bind/java depend on it. TODO: check gomobile bind's proguard rule - context lookup was implemented through reflection on android.app.AppGlobals class. Change-Id: Ieb6ad503eeef8c2c1c5836a21c667938c5a701a2 Reviewed-on: https://go-review.googlesource.com/12279 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Родитель
c6888a7bae
Коммит
136fa9bbbb
|
@ -45,8 +45,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|||
}
|
||||
|
||||
// Load classes here, which uses the correct ClassLoader.
|
||||
current_vm = vm;
|
||||
current_ctx = NULL;
|
||||
current_ctx_clazz = find_class(env, "org/golang/app/GoNativeActivity");
|
||||
current_ctx_clazz = (jclass)(*env)->NewGlobalRef(env, current_ctx_clazz);
|
||||
|
||||
|
@ -61,8 +59,10 @@ void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_
|
|||
JNIEnv* env = activity->env;
|
||||
|
||||
// Note that activity->clazz is mis-named.
|
||||
current_vm = activity->vm;
|
||||
current_ctx = (*env)->NewGlobalRef(env, activity->clazz);
|
||||
JavaVM* current_vm = activity->vm;
|
||||
jobject current_ctx = activity->clazz;
|
||||
|
||||
setCurrentContext(current_vm, (*env)->NewGlobalRef(env, current_ctx));
|
||||
|
||||
// Set TMPDIR.
|
||||
jmethodID gettmpdir = find_method(env, current_ctx_clazz, "getTmpdir", "()Ljava/lang/String;");
|
||||
|
|
|
@ -34,17 +34,6 @@ package app
|
|||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// current_vm is stored to initialize other cgo packages.
|
||||
//
|
||||
// As all the Go packages in a program form a single shared library,
|
||||
// there can only be one JNI_OnLoad function for iniitialization. In
|
||||
// OpenJDK there is JNI_GetCreatedJavaVMs, but this is not available
|
||||
// on android.
|
||||
JavaVM* current_vm;
|
||||
|
||||
// current_ctx is Android's android.context.Context. May be NULL.
|
||||
jobject current_ctx;
|
||||
|
||||
jclass current_ctx_clazz;
|
||||
|
||||
jclass app_find_class(JNIEnv* env, const char* name);
|
||||
|
@ -58,8 +47,14 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"golang.org/x/mobile/app/internal/callfn"
|
||||
"golang.org/x/mobile/internal/mobileinit"
|
||||
)
|
||||
|
||||
//export setCurrentContext
|
||||
func setCurrentContext(vm *C.JavaVM, ctx C.jobject) {
|
||||
mobileinit.SetCurrentContext(unsafe.Pointer(vm), unsafe.Pointer(ctx))
|
||||
}
|
||||
|
||||
//export callMain
|
||||
func callMain(mainPC uintptr) {
|
||||
for _, name := range []string{"TMPDIR", "PATH", "LD_LIBRARY_PATH"} {
|
||||
|
@ -186,25 +181,6 @@ func onConfigurationChanged(activity *C.ANativeActivity) {
|
|||
func onLowMemory(activity *C.ANativeActivity) {
|
||||
}
|
||||
|
||||
// Context holds global OS-specific context.
|
||||
//
|
||||
// Its extra methods are deliberately difficult to access because they must be
|
||||
// used with care. Their use implies the use of cgo, which probably requires
|
||||
// you understand the initialization process in the app package. Also care must
|
||||
// be taken to write both Android, iOS, and desktop-testing versions to
|
||||
// maintain portability.
|
||||
type Context struct{}
|
||||
|
||||
// AndroidContext returns a jobject for the app android.context.Context.
|
||||
func (Context) AndroidContext() unsafe.Pointer {
|
||||
return unsafe.Pointer(C.current_ctx)
|
||||
}
|
||||
|
||||
// JavaVM returns a JNI *JavaVM.
|
||||
func (Context) JavaVM() unsafe.Pointer {
|
||||
return unsafe.Pointer(C.current_vm)
|
||||
}
|
||||
|
||||
var (
|
||||
windowDestroyed = make(chan bool)
|
||||
windowCreated = make(chan *C.ANativeWindow)
|
||||
|
|
|
@ -61,13 +61,13 @@ import (
|
|||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/mobile/app"
|
||||
"golang.org/x/mobile/internal/mobileinit"
|
||||
)
|
||||
|
||||
var assetOnce sync.Once
|
||||
|
||||
func assetInit() {
|
||||
ctx := app.Context{}
|
||||
ctx := mobileinit.Context{}
|
||||
C.asset_manager_init(ctx.JavaVM(), ctx.AndroidContext())
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
package go;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
|
@ -24,6 +26,16 @@ public class Seq {
|
|||
Log.w("GoSeq", "LoadJNI class not found");
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO(hyangah): check proguard rule.
|
||||
Application appl = (Application)Class.forName("android.app.AppGlobals").getMethod("getInitialApplication").invoke(null, (Object[]) null);
|
||||
Context ctx = appl.getApplicationContext();
|
||||
setContext(ctx);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.w("GoSeq", "Global context not found:" + e);
|
||||
}
|
||||
|
||||
initSeq();
|
||||
new Thread("GoSeq") {
|
||||
public void run() { Seq.receive(); }
|
||||
|
@ -37,6 +49,8 @@ public class Seq {
|
|||
ensure(64);
|
||||
}
|
||||
|
||||
static native void setContext(Context ctx);
|
||||
|
||||
// Ensure that at least size bytes can be written to the Seq.
|
||||
// Any existing data in the buffer is preserved.
|
||||
public native void ensure(int size);
|
||||
|
|
|
@ -17,6 +17,12 @@ public class SeqTest extends AndroidTestCase {
|
|||
public SeqTest() {
|
||||
}
|
||||
|
||||
public void testAssets() {
|
||||
String want = "Hello, Assets.\n";
|
||||
String got = Testpkg.ReadAsset();
|
||||
assertEquals("Asset read", want, got);
|
||||
}
|
||||
|
||||
public void testAdd() {
|
||||
long res = Testpkg.Add(3, 4);
|
||||
assertEquals("Unexpected arithmetic failure", 7, res);
|
||||
|
|
|
@ -435,3 +435,12 @@ Java_go_Seq_recvRes(JNIEnv *env, jclass clazz, jint handle, jobject out_obj) {
|
|||
}
|
||||
RecvRes((int32_t)handle, out->buf, out->len);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_go_Seq_setContext(JNIEnv* env, jclass clazz, jobject ctx) {
|
||||
JavaVM* vm;
|
||||
if ((*env)->GetJavaVM(env, &vm) != 0) {
|
||||
LOG_FATAL("failed to get JavaVM");
|
||||
}
|
||||
setContext(vm, (*env)->NewGlobalRef(env, ctx));
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package java // import "golang.org/x/mobile/bind/java"
|
|||
|
||||
//#cgo LDFLAGS: -llog
|
||||
//#include <android/log.h>
|
||||
//#include <jni.h>
|
||||
//#include <stdint.h>
|
||||
//#include <string.h>
|
||||
//#include "seq_android.h"
|
||||
|
@ -16,6 +17,7 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"golang.org/x/mobile/bind/seq"
|
||||
"golang.org/x/mobile/internal/mobileinit"
|
||||
)
|
||||
|
||||
const maxSliceLen = 1<<31 - 1
|
||||
|
@ -178,3 +180,8 @@ func init() {
|
|||
seq.EncString = encodeString
|
||||
seq.DecString = decodeString
|
||||
}
|
||||
|
||||
//export setContext
|
||||
func setContext(vm *C.JavaVM, ctx C.jobject) {
|
||||
mobileinit.SetCurrentContext(unsafe.Pointer(vm), unsafe.Pointer(ctx))
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Hello, Assets.
|
|
@ -11,8 +11,12 @@ package testpkg
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"golang.org/x/mobile/asset"
|
||||
)
|
||||
|
||||
type I interface {
|
||||
|
@ -156,3 +160,17 @@ func Hello(r Receiver, name string) {
|
|||
func GarbageCollect() {
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
func ReadAsset() string {
|
||||
rc, err := asset.Open("hello.txt")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer rc.Close()
|
||||
|
||||
b, err := ioutil.ReadAll(rc)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ import (
|
|||
"log"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/mobile/app"
|
||||
"golang.org/x/mobile/internal/mobileinit"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -247,7 +247,7 @@ var (
|
|||
)
|
||||
|
||||
func initAL() {
|
||||
ctx := app.Context{}
|
||||
ctx := mobileinit.Context{}
|
||||
switch C.al_init(ctx.JavaVM(), ctx.AndroidContext(), &alHandle) {
|
||||
case C.AL_INIT_RESULT_OK:
|
||||
// No-op.
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package mobileinit
|
||||
|
||||
/*
|
||||
#include <jni.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// current_vm is stored to initialize other cgo packages.
|
||||
//
|
||||
// As all the Go packages in a program form a single shared library,
|
||||
// there can only be one JNI_OnLoad function for initialization. In
|
||||
// OpenJDK there is JNI_GetCreatedJavaVMs, but this is not available
|
||||
// on android.
|
||||
JavaVM* current_vm;
|
||||
|
||||
// current_ctx is Android's android.context.Context. May be NULL.
|
||||
jobject current_ctx;
|
||||
|
||||
// Set current_vm and current_ctx. The ctx passed in must be a global
|
||||
// reference instance.
|
||||
void set_vm_ctx(JavaVM* vm, jobject ctx) {
|
||||
current_vm = vm;
|
||||
current_ctx = ctx;
|
||||
// TODO: check leak
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// SetCurrentContext populates the global Context object with the specified
|
||||
// current JavaVM instance (vm) and android.context.Context object (ctx).
|
||||
// The android.context.Context object must be a global reference.
|
||||
func SetCurrentContext(vm, ctx unsafe.Pointer) {
|
||||
C.set_vm_ctx((*C.JavaVM)(vm), (C.jobject)(ctx))
|
||||
}
|
||||
|
||||
// TODO(hyangah): should the app package have Context? It may be useful for
|
||||
// external packages that need to access android context and vm.
|
||||
|
||||
// Context holds global OS-specific context.
|
||||
//
|
||||
// Its extra methods are deliberately difficult to access because they must be
|
||||
// used with care. Their use implies the use of cgo, which probably requires
|
||||
// you understand the initialization process in the app package. Also care must
|
||||
// be taken to write both Android, iOS, and desktop-testing versions to
|
||||
// maintain portability.
|
||||
type Context struct{}
|
||||
|
||||
// AndroidContext returns a jobject for the app android.context.Context.
|
||||
func (Context) AndroidContext() unsafe.Pointer {
|
||||
return unsafe.Pointer(C.current_ctx)
|
||||
}
|
||||
|
||||
// JavaVM returns a JNI *JavaVM.
|
||||
func (Context) JavaVM() unsafe.Pointer {
|
||||
return unsafe.Pointer(C.current_vm)
|
||||
}
|
|
@ -5,5 +5,5 @@
|
|||
// Package mobileinit contains common initialization logic for mobile platforms
|
||||
// that is relevant to both all-Go apps and gobind-based apps.
|
||||
//
|
||||
// Long-term, any code in this package should consider moving into Go stdlib.
|
||||
// Long-term, some code in this package should consider moving into Go stdlib.
|
||||
package mobileinit
|
||||
|
|
Загрузка…
Ссылка в новой задаче