Android: Add APK reading, closing app. Fix JNI env not attached to thread.

This commit is contained in:
Alberto Torres 2024-12-04 13:32:01 +01:00
parent e0b02d2708
commit 12940dad1d
2 changed files with 47 additions and 2 deletions

View file

@ -97,5 +97,7 @@ when defined(android):
export platform.myouAndroidGetJniEnv
export platform.myouAndroidGetInternalDataPath
export platform.myouAndroidGetExternalDataPath
export platform.myouAndroidAPKFilePointerLength
export platform.myouCloseMobileApp
export platform.myouSetKeyboardVisible

View file

@ -324,8 +324,17 @@ proc myouAndroidGetJniEnv*(): pointer =
# Ussing offsets from ANativeActivity
let vm = cast[ptr ptr array[7, pointer]](activity[1])
# Using offsets from jni.h
let GetEnv = cast[proc(vm: pointer, penv: var pointer, version: int32): int32 {.cdecl, gcsafe.}](vm[][6])
discard GetEnv(vm, result, 0x00010006'i32)
let getEnv = cast[proc(vm: pointer, penv: var pointer, version: int32): int32 {.cdecl, gcsafe.}](vm[][6])
let attachCurrentThread = cast[proc(vm: pointer, penv: ptr pointer, args: pointer): int32 {.cdecl, gcsafe.}](vm[][4])
let status = getEnv(vm, result, 0x00010006'i32)
if status == -2: # JNI_EDETACHED
# Attach thread to VM
if attachCurrentThread(vm, result.addr, nil) != 0:
echo "could not attach thread to VM"
result = nil
elif status != 0: # JNI_OK
result = nil
# TODO: do we ever need to detach a thread from the VM?
proc myouAndroidGetInternalDataPath*(): string =
when defined(android):
@ -337,5 +346,39 @@ proc myouAndroidGetExternalDataPath*(): string =
let activity = cast[ptr array[6, cstring]](window.glfmAndroidGetActivity())
return $activity[5]
when defined(android):
proc AAssetManager_open(asset_manager: pointer, filename: cstring, mode: int32): pointer {.importc,cdecl.}
proc AAsset_close(asset: pointer) {.importc,cdecl.}
proc AAsset_getBuffer(asset: pointer): pointer {.importc,cdecl.}
proc AAsset_getLength64(asset: pointer): int64 {.importc,cdecl.}
proc ANativeActivity_finish(activity: pointer) {.importc,cdecl.}
type myouAAssetObj = object
asset: pointer
p*: pointer
len*: int
type myouAAsset* = ref myouAAssetObj
proc `=destroy`(x: var myouAAssetObj) =
if x.asset != nil:
AAsset_close(x.asset)
x.asset = nil
proc myouAndroidAPKFilePointerLength*(path: string): myouAAsset =
let activity = cast[ptr array[9, pointer]](window.glfmAndroidGetActivity())
# Ussing offsets from ANativeActivity, assuming all pointers are aligned
let asset_manager = activity[8]
let asset = AAssetManager_open(asset_manager, path.cstring, 3) # 3 = buffer mode
if asset == nil:
echo "not found in APK: ", path
return myouAAsset()
let p = AAsset_getBuffer(asset)
let len = AAsset_getLength64(asset).int
myouAAsset(asset: asset, p: p, len: len)
proc myouSetKeyboardVisible*(show: bool) =
window.glfmSetKeyboardVisible(show)
proc myouCloseMobileApp*() =
ANativeActivity_finish(window.glfmAndroidGetActivity())