From 3fb88500a2bd73a70bef4087211096bd77dcbcf4 Mon Sep 17 00:00:00 2001 From: Larpon Date: Wed, 22 Jun 2022 20:38:27 +0200 Subject: [PATCH] os: improve Android interop (#14827) --- .github/workflows/ci_cross.yml | 12 +---- vlib/os/os_android.c.v | 93 ++++++++++++++++++++++++++++------ 2 files changed, 79 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci_cross.yml b/.github/workflows/ci_cross.yml index 59af9b2a8..d11f2c95a 100644 --- a/.github/workflows/ci_cross.yml +++ b/.github/workflows/ci_cross.yml @@ -42,11 +42,6 @@ jobs: ./v -os windows cmd/v ./v -os windows examples/2048/2048.v - - name: Compile to raw Android (non-graphic) compatible - run: | - # Test that V can compile non-graphic app to Android compatible code *without* using the -apk flag - ./v -os android -gc none examples/toml.v - linux-cross: runs-on: ubuntu-20.04 if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v' @@ -64,6 +59,7 @@ jobs: sudo apt-get install --quiet -y libssl-dev sqlite3 libsqlite3-dev sudo apt-get install --quiet -y mingw-w64 wine-stable winetricks ## sudo apt-get install --quiet -y wine32 + - name: Turn off the wine crash dialog run: winetricks nocrashdialog @@ -95,12 +91,6 @@ jobs: ./v -os windows examples/2048/2048.v ls -lart examples/2048/2048.exe - - name: toml.v can be compiled to raw Android C - run: | - # Test that V can compile non-graphic app to Android compatible code *without* using the -apk flag - ./v -os android -gc none examples/toml.v - - windows-cross: runs-on: windows-2019 if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v' diff --git a/vlib/os/os_android.c.v b/vlib/os/os_android.c.v index d4588d227..0ef6fb2de 100644 --- a/vlib/os/os_android.c.v +++ b/vlib/os/os_android.c.v @@ -1,41 +1,104 @@ module os -struct C.AAsset { +pub enum AssetMode { + buffer = C.AASSET_MODE_BUFFER // Caller plans to ask for a read-only buffer with all data. + random = C.AASSET_MODE_RANDOM // Read chunks, and seek forward and backward. + streaming = C.AASSET_MODE_STREAMING // Read sequentially, with an occasional forward seek. + unknown = C.AASSET_MODE_UNKNOWN // No specific information about how data will be accessed. } -struct C.AAssetManager { +struct C.ANativeActivity { + assetManager &AssetManager // Pointer to the Asset Manager instance for the application. + clazz voidptr // (jobject) The NativeActivity object handle. + env voidptr // (JNIEnv *) JNI context for the main thread of the app. + externalDataPath &char // Path to this application's external (removable/mountable) data directory. + instance voidptr // This is the native instance of the application. + internalDataPath &char // Path to this application's internal data directory. + obbPath &char // Available starting with Honeycomb: path to the directory containing the application's OBB files (if any). + sdkVersion int // The platform's SDK version code. + vm voidptr // (JavaVM *) The global handle on the process's Java VM. } -struct C.ANativeActivity { - assetManager voidptr +// NativeActivity defines the native side of an android.app.NativeActivity. +pub type NativeActivity = C.ANativeActivity + +struct C.AAssetManager { } +// AssetManager provides access to an application's raw assets by creating Asset objects. +pub type AssetManager = C.AAssetManager + fn C.AAssetManager_open(&C.AAssetManager, &char, int) &C.AAsset +// open opens an Android `Asset` +pub fn (am &AssetManager) open(filename string, mode AssetMode) !&Asset { + asset := C.AAssetManager_open(am, filename.str, int(mode)) + if isnil(asset) { + return error('file `$filename` not found') + } + return asset +} + +struct C.AAsset { +} + +pub type Asset = C.AAsset + +fn C.AAsset_getBuffer(&C.AAsset) voidptr + +// get_buffer returns a pointer to a buffer holding the entire contents of the asset. +pub fn (a &Asset) get_buffer() voidptr { + return C.AAsset_getBuffer(a) +} + fn C.AAsset_getLength(&C.AAsset) int -fn C.AAsset_read(&C.AAsset, voidptr, int) int +// get_length returns the total size of the asset data. +pub fn (a &Asset) get_length() int { + return C.AAsset_getLength(a) +} + +fn C.AAsset_getLength64(&C.AAsset) i64 + +// get_length_64 returns the total size of the asset data. +// get_length_64 returns the size using a 64-bit number insted of 32-bit as `get_length`. +pub fn (a &Asset) get_length_64() i64 { + return C.AAsset_getLength64(a) +} + +fn C.AAsset_read(&C.AAsset, voidptr, usize) int + +// read attempts to read 'count' bytes of data from the current offset. +// read returns the number of bytes read, zero on EOF, or < 0 on error. +pub fn (a &Asset) read(buffer voidptr, count usize) int { + return C.AAsset_read(a, buffer, count) +} fn C.AAsset_close(&C.AAsset) -pub fn read_apk_asset(file string) ?[]u8 { +// close closes the asset, freeing all associated resources. +pub fn (a &Asset) close() { + C.AAsset_close(a) +} + +// read_apk_asset returns all the data located at `path`. +// `path` is expected to be relative to the `assets` +pub fn read_apk_asset(path string) ![]u8 { $if apk { - act := &C.ANativeActivity(C.sapp_android_get_native_activity()) + act := &NativeActivity(C.sapp_android_get_native_activity()) if isnil(act) { - return error('Could not get reference to Android activity') - } - asset := C.AAssetManager_open(&C.AAssetManager(act.assetManager), file.str, C.AASSET_MODE_STREAMING) - if isnil(asset) { - return error('File `$file` not found') + return error('could not get reference to Android activity') } - len := C.AAsset_getLength(asset) + asset_manager := &AssetManager(act.assetManager) + asset := asset_manager.open(path, .streaming)! + len := asset.get_length() buf := []u8{len: len} for { - if C.AAsset_read(asset, buf.data, len) > 0 { + if asset.read(buf.data, usize(len)) > 0 { break } } - C.AAsset_close(asset) + asset.close() return buf } $else { return error(@FN + ' can only be used with APK/AAB packaged Android apps') -- 2.30.2