Git Product home page Git Product logo

zigandroidtemplate's Introduction

Android Apps in Zig

Project banner

This repository contains multiple examples of creating a minimal Android app in Zig.

Examples

There are 4 different examples. The examples have no dependencies on C code except for the android libraries, so they can be considered pure Zig apps.

To select which example to build and run, pass the example flag (e.g. -Dexample=egl). Valid values for the example flag are egl, minimal, textview, and invocationhandler.

We're running a CI that will verify the build for Windows, macOS and Linux:

CI

Minimal

examples/minimal includes just enough code to get the app running.

EGL

examples/egl/ initializes OpenGL and renders a color cycle. Touchscreen events will activate a sine wave synth and be displayed as small circles beneath the fingers that will fade as soon as no event for the same finger will happen again.

The code contains some commented examples on how to interface with the JNI to use advanced features of the ANativeActivity.

Textview

examples/textview/ creates a Textview component with Android's built-in UI to display "Hello, World!".

InvocationHandler

examples/invocationhandler builds on the textview example. It shows how to pass a callback to the JNI by creating a button component that reacts to being pressed.

Presentation

There is a FOSDEM Talk you can watch here:

Since the time of recording ZigAndroidTemplate has changed in some major ways.

What's missing

  • Configuration management example
  • Save/load app state example

Requirements & Build

You need the Android SDK installed together with the Android NDK.

You also need adb and a Java SDK installed (required for jarsigner).

Now you need to generate yourself a keystore to sign your apps. For debugging purposes, the build script contains a helper. Just invoke zig build keystore to generate yourself a debug keystore that can be used with later build invocations.

Note that the build file might ask you to configure some paths. Do as requested and just run the build again, it should work then.

If all of the above is done, you should be able to build the app by running zig build.

There are convenience options with zig build push (installs the app on a connected phone) and zig build run (which installs, then runs the app).

Quick Start

Install the sdkmanager and invoke the following command line:

# Android Platforms for your target Android version
# Min version: Android 5
sdkmanager --install "platforms;android-21"
# you can install other versions as well
# remember to set it like `zig build -Dandroid=android99`

sdkmanager --install "build-tools;33.0.1"
sdkmanager --install "ndk;25.1.8937393"
zig build keystore install run

This should build an APK and install it on your connected phone if possible.

Getting started

Check out the build.zig to see how to build a new android app. The examples folder has multiple examples for making minimal android apps.

Credits

Huge thanks to @cnlohr to create rawdrawandroid and making this project possible!

zigandroidtemplate's People

Contributors

deecellar avatar desttinghim avatar iacore avatar ilidemi avatar jmrico01 avatar masterq32 avatar spexguy avatar zenith391 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

zigandroidtemplate's Issues

Some elements not rendered

I am encountering a strange issue where some of the elements in the example application are not rendering - in particular, the spinning zig logo and the "glow" on touch. Everything else seems to be working correctly. It only seems to be an issue with my tablet, and not my phone. The issue has been occurring since I got the app running on my tablet, so it's unlikely to be due to a change in the code.

Truncated logcat output:
log.txt

EDIT: After reading more of the code, the issue appears to be the shaders. The only thing rendering is the clear color.

Need help: Got a runtime error while trying to run ziggy.apk on my device

I was able to compile and install the app on real device using zig-7.0.1. But got following error while running the app. I have no idea how to fix it.

04-30 14:24:12.938 29311 29311 E AndroidRuntime: java.lang.UnsatisfiedLinkError: Unable to load native library "/data/app/~~sNfX4kgZkQxtloUXpGUHxg==/net.random_projects.ziggy-m6JaMHjKcUYYTYw2n27jaQ==/lib/arm64/libziggy.so": dlopen failed: cannot locate symbol "dl_iterate_phdr" referenced by "/data/app/~~sNfX4kgZkQxtloUXpGUHxg==/net.random_projects.ziggy-m6JaMHjKcUYYTYw2n27jaQ==/lib/arm64/libziggy.so"...

is it supposed to work in Windows too? (failing currently)

I'm on Windows 7 64bit, using the latest zig that doesn't complain about something missing in kernel32.dll(or so) and these are the errors so far:

c:\zat\ZigAndroidTemplate-master>rm -r zig-cache

c:\zat\ZigAndroidTemplate-master>zig build
C:\zat\ZigAndroidTemplate-master\build.zig:119:29: error: expected type 'std.bui
ld.FileSource', found '*const [17:0]u8'
    aarch64_exe.libc_file = "./libc/arm64.conf";
                            ^
C:\zig\lib\std\build.zig:1333:24: note: std.build.FileSource declared here
pub const FileSource = union(enum) {
                       ^
C:\zig\lib\std\special\build_runner.zig:194:24: note: referenced here
        .ErrorUnion => try root.build(builder),
                       ^
C:\zat\ZigAndroidTemplate-master\build.zig:63:21: error: expected 3 argument(s),
 found 2
    exe.defineCMacro("ANDROID");
                    ^
C:\zig\lib\std\build.zig:1791:9: note: declared here
    pub fn defineCMacro(self: *LibExeObjStep, name: []const u8, value: ?[]const
u8) void {
        ^

c:\zat\ZigAndroidTemplate-master>zig version
0.9.0-dev.749+259f3458a

I'm new to zig and haven't done any program in it, yet. But I want to start with ... this :)
Any hints on how to fix the above ?
I assume, somehow, that this would all work if I were trying it on Linux?

I'm happy to provide more info, also I'm very interested in making this all work in Windows for I want to make at least 2 apk apps by using zig and this ZigAndroidTemplate would be the way I would learn how.

Thanks in advance.

Use Android SDK apksigner instead JDK jarsigner

Hi again,

Is there a reason to not use the apksigner of SDK ?

Like this:
/usr/lib/android-sdk/build-tools/33.0.0/apksigner sign --ks .build_config/android.keystore --ks-key-alias default --ks-pass pass:ziguana app-template.apk

Following a patch : Works for me, perhaps usefull for someone.

diff --git a/Sdk.zig b/Sdk.zig
index 58e3b50..5fbead9 100644
--- a/Sdk.zig
+++ b/Sdk.zig
@@ -42,7 +42,7 @@ pub fn init(b: *Builder, user_config: ?UserConfig, versions: ToolchainVersions)
         const zipalign = std.fs.path.join(b.allocator, &[_][]const u8{ actual_user_config.android_sdk_root, "build-tools", versions.build_tools_version, "zipalign" ++ exe }) catch unreachable;
         const aapt = std.fs.path.join(b.allocator, &[_][]const u8{ actual_user_config.android_sdk_root, "build-tools", versions.build_tools_version, "aapt" ++ exe }) catch unreachable;
         const adb = std.fs.path.join(b.allocator, &[_][]const u8{ actual_user_config.android_sdk_root, "platform-tools", "adb" ++ exe }) catch unreachable;
-        const jarsigner = std.fs.path.join(b.allocator, &[_][]const u8{ actual_user_config.java_home, "bin", "jarsigner" ++ exe }) catch unreachable;
+        const jarsigner = std.fs.path.join(b.allocator, &[_][]const u8{ actual_user_config.android_sdk_root, "build-tools", versions.build_tools_version, "apksigner" ++ exe }) catch unreachable;
         const keytool = std.fs.path.join(b.allocator, &[_][]const u8{ actual_user_config.java_home, "bin", "keytool" ++ exe }) catch unreachable;

         break :blk SystemTools{
@@ -697,17 +680,17 @@ pub fn compressApk(sdk: Sdk, input_apk_file: []const u8, output_apk_file: []cons
 pub fn signApk(sdk: Sdk, apk_file: []const u8, key_store: KeyStore) *Step {
     const sign_apk = sdk.b.addSystemCommand(&[_][]const u8{
         sdk.system_tools.jarsigner,
-        "-sigalg",
-        "SHA1withRSA",
-        "-digestalg",
-        "SHA1",
-        "-verbose",
-        "-keystore",
+        "sign",
+        "--ks",
         key_store.file,
-        "-storepass",
-        key_store.password,
-        sdk.b.pathFromRoot(apk_file),
+        "--ks-key-alias",
         key_store.alias,
+        "--ks-pass",
+        std.mem.concat(sdk.b.allocator, u8, &[_][]const u8{
+            "pass:",
+            key_store.password,
+        }) catch unreachable,
+        sdk.b.pathFromRoot(apk_file),
     });
     return &sign_apk.step;
 }

Update README

The README is out of sync with the current state of the code. It should be updated. I'm willing to work on this, just putting this here as a TODO.

How debug?

Do anyone figure out how to debug apps using this build system?

error: container 'AndroidApp' has no member called 'init'

and error: container '.build_options' has no member called 'app_name' are the two errors I'm getting on Artix Linux (Arch Linux based).

I'm not sure what more info to give, please let me know?

artixvbox:[user]:~/zat/ZigAndroidTemplate-master$ time zig build
CrossTarget{ .cpu_arch = Arch.aarch64, .cpu_model = CpuModel{ .baseline = void }, .cpu_features_add = Set{ .ints = { 0, 0, 67108864, 0, 0 } }, .cpu_features_sub = Set{ .ints = { 0, 0, 0, 0, 0 } }, .os_tag = Tag.linux, .os_version_min = null, .os_version_max = null, .glibc_version = null, .abi = null, .dynamic_linker = DynamicLinker{ .buffer = { 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170 }, .max_byte = null } }
./src/android-support.zig:45:23: error: container 'AndroidApp' has no member called 'init'
    app.* = AndroidApp.init(
                      ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:164:16: note: called from here
            log(.emerg, scope, format, args);
               ^
./src/android-support.zig:115:18: note: called from here
    std.log.emerg("PANIC: {s}\n", .{message});
                 ^
./src/android-support.zig:114:83: note: called from here
pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
                                                                                  ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:164:16: note: called from here
            log(.emerg, scope, format, args);
               ^
./src/android-support.zig:118:22: note: called from here
        std.log.emerg("{}\n", .{st});
                     ^
./src/android-support.zig:114:83: note: called from here
pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
                                                                                  ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:164:16: note: called from here
            log(.emerg, scope, format, args);
               ^
./src/android-support.zig:88:34: note: called from here
                    std.log.emerg("{s}", .{self.line_buffer[0..self.line_len]});
                                 ^
./src/android-support.zig:83:59: note: called from here
    fn write(self: *LogWriter, buffer: []const u8) !usize {
                                                          ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:164:16: note: called from here
            log(.emerg, scope, format, args);
               ^
./src/android-support.zig:125:26: note: called from here
            std.log.emerg("failed to write stack trace: {s}", .{err});
                         ^
./src/android-support.zig:114:83: note: called from here
pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
                                                                                  ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:164:16: note: called from here
            log(.emerg, scope, format, args);
               ^
./src/android-support.zig:128:22: note: called from here
        std.log.emerg("failed to get debug info: {s}", .{err});
                     ^
./src/android-support.zig:114:83: note: called from here
pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
                                                                                  ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:232:16: note: called from here
            log(.debug, scope, format, args);
               ^
./src/android-support.zig:34:18: note: called from here
    app_log.debug("Starting on Android Version {}\n", .{
                 ^
./src/android-support.zig:22:133: note: called from here
export fn ANativeActivity_onCreate(activity: *android.ANativeActivity, savedState: ?[*]u8, savedStateSize: usize) callconv(.C) void {
                                                                                                                                    ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:164:16: note: called from here
            log(.emerg, scope, format, args);
               ^
./src/android-support.zig:39:22: note: called from here
        app_log.emerg("Could not create new AndroidApp: OutOfMemory!\n", .{});
                     ^
./src/android-support.zig:22:133: note: called from here
export fn ANativeActivity_onCreate(activity: *android.ANativeActivity, savedState: ?[*]u8, savedStateSize: usize) callconv(.C) void {
                                                                                                                                    ^
./src/main.zig:107:35: error: expected 2 argument(s), found 1
        self.egl = EGLContext.init(window) catch |err| blk: {
                                  ^
./src/egl.zig:19:9: note: declared here
    pub fn init(window: *android.ANativeWindow, version: Version) !Self {
        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:232:16: note: called from here
            log(.debug, scope, format, args);
               ^
./src/android-support.zig:197:30: note: called from here
                app_log.debug("ANativeActivity callback onSaveInstanceState not available on {s}", .{@typeName(App)});
                             ^
./src/android-support.zig:186:105: note: called from here
        fn onSaveInstanceState(activity: *android.ANativeActivity, outSize: *usize) callconv(.C) ?[*]u8 {
                                                                                                        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:232:16: note: called from here
            log(.debug, scope, format, args);
               ^
./src/android-support.zig:181:30: note: called from here
                app_log.debug("ANativeActivity callback {s} not available on {s}", .{ func, @typeName(App) });
                             ^
./src/android-support.zig:210:19: note: called from here
            invoke(activity, "onStart", .{});
                  ^
./src/android-support.zig:209:74: note: called from here
        fn onStart(activity: *android.ANativeActivity) callconv(.C) void {
                                                                         ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:232:16: note: called from here
            log(.debug, scope, format, args);
               ^
./src/android-support.zig:181:30: note: called from here
                app_log.debug("ANativeActivity callback {s} not available on {s}", .{ func, @typeName(App) });
                             ^
./src/android-support.zig:213:19: note: called from here
            invoke(activity, "onResume", .{});
                  ^
./src/android-support.zig:212:75: note: called from here
        fn onResume(activity: *android.ANativeActivity) callconv(.C) void {
                                                                          ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:232:16: note: called from here
            log(.debug, scope, format, args);
               ^
./src/android-support.zig:181:30: note: called from here
                app_log.debug("ANativeActivity callback {s} not available on {s}", .{ func, @typeName(App) });
                             ^
./src/android-support.zig:216:19: note: called from here
            invoke(activity, "onPause", .{});
                  ^
./src/android-support.zig:215:74: note: called from here
        fn onPause(activity: *android.ANativeActivity) callconv(.C) void {
                                                                         ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:232:16: note: called from here
            log(.debug, scope, format, args);
               ^
./src/android-support.zig:181:30: note: called from here
                app_log.debug("ANativeActivity callback {s} not available on {s}", .{ func, @typeName(App) });
                             ^
./src/android-support.zig:219:19: note: called from here
            invoke(activity, "onStop", .{});
                  ^
./src/android-support.zig:218:73: note: called from here
        fn onStop(activity: *android.ANativeActivity) callconv(.C) void {
                                                                        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:232:16: note: called from here
            log(.debug, scope, format, args);
               ^
./src/android-support.zig:181:30: note: called from here
                app_log.debug("ANativeActivity callback {s} not available on {s}", .{ func, @typeName(App) });
                             ^
./src/android-support.zig:228:19: note: called from here
            invoke(activity, "onWindowFocusChanged", .{(hasFocus != 0)});
                  ^
./src/android-support.zig:227:104: note: called from here
        fn onWindowFocusChanged(activity: *android.ANativeActivity, hasFocus: c_int) callconv(.C) void {
                                                                                                       ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:232:16: note: called from here
            log(.debug, scope, format, args);
               ^
./src/android-support.zig:181:30: note: called from here
                app_log.debug("ANativeActivity callback {s} not available on {s}", .{ func, @typeName(App) });
                             ^
./src/android-support.zig:234:19: note: called from here
            invoke(activity, "onNativeWindowResized", .{window});
                  ^
./src/android-support.zig:233:120: note: called from here
        fn onNativeWindowResized(activity: *android.ANativeActivity, window: *android.ANativeWindow) callconv(.C) void {
                                                                                                                       ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:232:16: note: called from here
            log(.debug, scope, format, args);
               ^
./src/android-support.zig:181:30: note: called from here
                app_log.debug("ANativeActivity callback {s} not available on {s}", .{ func, @typeName(App) });
                             ^
./src/android-support.zig:237:19: note: called from here
            invoke(activity, "onNativeWindowRedrawNeeded", .{window});
                  ^
./src/android-support.zig:236:125: note: called from here
        fn onNativeWindowRedrawNeeded(activity: *android.ANativeActivity, window: *android.ANativeWindow) callconv(.C) void {
                                                                                                                            ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:232:16: note: called from here
            log(.debug, scope, format, args);
               ^
./src/android-support.zig:181:30: note: called from here
                app_log.debug("ANativeActivity callback {s} not available on {s}", .{ func, @typeName(App) });
                             ^
./src/android-support.zig:249:19: note: called from here
            invoke(activity, "onContentRectChanged", .{rect});
                  ^
./src/android-support.zig:248:115: note: called from here
        fn onContentRectChanged(activity: *android.ANativeActivity, rect: *const android.ARect) callconv(.C) void {
                                                                                                                  ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:232:16: note: called from here
            log(.debug, scope, format, args);
               ^
./src/android-support.zig:181:30: note: called from here
                app_log.debug("ANativeActivity callback {s} not available on {s}", .{ func, @typeName(App) });
                             ^
./src/android-support.zig:222:19: note: called from here
            invoke(activity, "onConfigurationChanged", .{});
                  ^
./src/android-support.zig:221:89: note: called from here
        fn onConfigurationChanged(activity: *android.ANativeActivity) callconv(.C) void {
                                                                                        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:232:16: note: called from here
            log(.debug, scope, format, args);
               ^
./src/android-support.zig:181:30: note: called from here
                app_log.debug("ANativeActivity callback {s} not available on {s}", .{ func, @typeName(App) });
                             ^
./src/android-support.zig:225:19: note: called from here
            invoke(activity, "onLowMemory", .{});
                  ^
./src/android-support.zig:224:78: note: called from here
        fn onLowMemory(activity: *android.ANativeActivity) callconv(.C) void {
                                                                             ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:195:16: note: called from here
            log(.err, scope, format, args);
               ^
./src/egl.zig:24:24: note: called from here
            std.log.err("Error: No display found!\n", .{});
                       ^
./src/egl.zig:19:73: note: called from here
    pub fn init(window: *android.ANativeWindow, version: Version) !Self {
                                                                        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:195:16: note: called from here
            log(.err, scope, format, args);
               ^
./src/egl.zig:31:24: note: called from here
            std.log.err("Error: eglInitialise failed!\n", .{});
                       ^
./src/egl.zig:19:73: note: called from here
    pub fn init(window: *android.ANativeWindow, version: Version) !Self {
                                                                        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:223:16: note: called from here
            log(.info, scope, format, args);
               ^
./src/egl.zig:35:21: note: called from here
        std.log.info(
                    ^
./src/egl.zig:19:73: note: called from here
    pub fn init(window: *android.ANativeWindow, version: Version) !Self {
                                                                        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:195:16: note: called from here
            log(.err, scope, format, args);
               ^
./src/egl.zig:73:24: note: called from here
            std.log.err("Error: eglChooseConfig failed: 0x{X:0>4}\n", .{c.eglGetError()});
                       ^
./src/egl.zig:19:73: note: called from here
    pub fn init(window: *android.ANativeWindow, version: Version) !Self {
                                                                        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:223:16: note: called from here
            log(.info, scope, format, args);
               ^
./src/egl.zig:77:21: note: called from here
        std.log.info("Config: {}\n", .{num_config});
                    ^
./src/egl.zig:19:73: note: called from here
    pub fn init(window: *android.ANativeWindow, version: Version) !Self {
                                                                        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:195:16: note: called from here
            log(.err, scope, format, args);
               ^
./src/egl.zig:83:20: note: called from here
            log.err("Error: eglCreateContext failed: 0x{X:0>4}\n", .{c.eglGetError()});
                   ^
./src/egl.zig:19:73: note: called from here
    pub fn init(window: *android.ANativeWindow, version: Version) !Self {
                                                                        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:223:16: note: called from here
            log(.info, scope, format, args);
               ^
./src/egl.zig:88:21: note: called from here
        std.log.info("Context created: {}\n", .{context});
                    ^
./src/egl.zig:19:73: note: called from here
    pub fn init(window: *android.ANativeWindow, version: Version) !Self {
                                                                        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:223:16: note: called from here
            log(.info, scope, format, args);
               ^
./src/egl.zig:95:21: note: called from here
        std.log.info("Screen Resolution: {}x{}\n", .{ android_width, android_height });
                    ^
./src/egl.zig:19:73: note: called from here
    pub fn init(window: *android.ANativeWindow, version: Version) !Self {
                                                                        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:223:16: note: called from here
            log(.info, scope, format, args);
               ^
./src/egl.zig:100:21: note: called from here
        std.log.info("Got Surface: {}\n", .{egl_surface});
                    ^
./src/egl.zig:19:73: note: called from here
    pub fn init(window: *android.ANativeWindow, version: Version) !Self {
                                                                        ^
./src/android-support.zig:160:22: error: container '.build_options' has no member called 'app_name'
        build_options.app_name.ptr,
                     ^
/usr/lib/zig/std/log.zig:128:21: note: called from here
            root.log(message_level, scope, format, args);
                    ^
/usr/lib/zig/std/log.zig:195:16: note: called from here
            log(.err, scope, format, args);
               ^
./src/egl.zig:103:24: note: called from here
            std.log.err("Error: eglCreateWindowSurface failed: 0x{X:0>4}\n", .{c.eglGetError()});
                       ^
./src/egl.zig:19:73: note: called from here
    pub fn init(window: *android.ANativeWindow, version: Version) !Self {
                                                                        ^
zig-gles2-demo...The following command exited with error code 1:
/usr/bin/zig build-lib /home/user/zat/ZigAndroidTemplate-master/src/main.zig -lGLESv3 -lEGL -landroid -llog -lc --pkg-begin build_options /home/user/zat/ZigAndroidTemplate-master/zig-cache/zig-gles2-demo_build_options.zig --pkg-end -ffunction-sections --libc /home/user/zat/ZigAndroidTemplate-master/libc/arm64.conf --cache-dir /home/user/zat/ZigAndroidTemplate-master/zig-cache --global-cache-dir /home/user/.cache/zig --name zig-gles2-demo --version 1 -dynamic -fcompiler-rt -target aarch64-linux -mcpu=generic+v8a -I /home/user/zat/ZigAndroidTemplate-master/src -I /home/user/Android/Sdk/ndk/21.1.6352462/sysroot/usr/include -I /home/user/Android/Sdk/ndk/21.1.6352462/sysroot/usr/include/aarch64-linux-android -L /home/user/Android/Sdk/ndk/21.1.6352462/platforms/android-29/arch-arm64/usr/lib -D ANDROID -fPIC --enable-cache 
error: the following build command failed with exit code 1:
/home/user/zat/ZigAndroidTemplate-master/zig-cache/o/666e5446e07e99f433499102b29ef746/build /usr/bin/zig /home/user/zat/ZigAndroidTemplate-master /home/user/zat/ZigAndroidTemplate-master/zig-cache /home/user/.cache/zig

real    0m23.754s
user    0m21.258s
sys     0m1.950s

Even less Java :)

I'm curious if you've seen my experimental project dali and its example app? I also presented some kind of a talk about it on the virtual Nim conference. In shortest words, in case you're interested, it's possible to write Android apps completely without using JVM at all, even not using it in the compilation environment! I'm happy to talk more if you'd like to go deeper into the rabbit hole ;P

Enhance Quick-Start Documentation and NDK compatiblity ?

Hi,
at first thanks for this usefull template.

Perhaps this hels someone using this as base.

Documentation Quick-Start:
Installting android sdk,ndk,platforms using dpkg/apt sample:
apt install google-android-ndk-r25-installer install google-android-platform-30-installer google-android-build-tools-33.0.0-installer

for jarsigner:
apt install openjdk-19-jdk-headless

Using Build Tools > 22

The sysroot moved to /toolchains/llvm/prebuilt//sysroot starting with NDK r19. r22 removed the deprecated sysroot and platforms directories from the top-level of the NDK.

So this dirty hack to Sdk.zig are working (not perfect but perhaps a Hint for anyone with more experience):

diff --git a/Sdk.zig b/Sdk.zig
index 58e3b50..a6eb83a 100644
--- a/Sdk.zig
+++ b/Sdk.zig
@@ -81,9 +81,9 @@ pub fn init(b: *Builder, user_config: ?UserConfig, versions: ToolchainVersions)
 }

 pub const ToolchainVersions = struct {
-    android_sdk_version: u16 = 28,
-    build_tools_version: []const u8 = "28.0.3",
-    ndk_version: []const u8 = "21.1.6352462",
+    android_sdk_version: u16 = 30,
+    build_tools_version: []const u8 = "33.0.0",
+    ndk_version: []const u8 = "25.0.8775105",

     pub fn androidSdkString(self: ToolchainVersions, buf: *[5]u8) []u8 {
         return std.fmt.bufPrint(buf, "{d}", .{self.android_sdk_version}) catch unreachable;
@@ -561,7 +561,7 @@ pub fn compileAppLibrary(

     exe.defineCMacro("ANDROID", null);

-    const include_dir = std.fs.path.resolve(sdk.b.allocator, &[_][]const u8{ ndk_root, "sysroot/usr/include" }) catch unreachable;
+    const include_dir = std.fs.path.resolve(sdk.b.allocator, &[_][]const u8{ ndk_root, "toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include" }) catch unreachable;
     exe.addIncludeDir(include_dir);

     exe.linkLibC();
@@ -572,66 +572,49 @@ pub fn compileAppLibrary(
     exe.setBuildMode(mode);

     const TargetConfig = struct {
-        lib_dir: []const u8,
         include_dir: []const u8,
-        libgcc_dir: []const u8,
         out_dir: []const u8,
         target: std.zig.CrossTarget,
     };

     const config: TargetConfig = switch (target) {
         .aarch64 => TargetConfig{
-            .lib_dir = "arch-arm64/usr/lib",
-            .libgcc_dir = "aarch64-linux-android-4.9",
             .include_dir = "aarch64-linux-android",
             .out_dir = "arm64-v8a",
             .target = zig_targets.aarch64,
         },
         .arm => TargetConfig{
-            .lib_dir = "arch-arm/usr/lib",
-            .libgcc_dir = "arm-linux-androideabi-4.9",
             .include_dir = "arm-linux-androideabi",
             .out_dir = "armeabi",
             .target = zig_targets.arm,
         },
         .x86 => TargetConfig{
-            .lib_dir = "arch-x86/usr/lib",
-            .libgcc_dir = "x86-4.9",
             .include_dir = "i686-linux-android",
             .out_dir = "x86",
             .target = zig_targets.x86,
         },
         .x86_64 => TargetConfig{
-            .lib_dir = "arch-x86_64/usr/lib64",
-            .libgcc_dir = "x86_64-4.9",
             .include_dir = "x86_64-linux-android",
             .out_dir = "x86_64",
             .target = zig_targets.x86_64,
         },
     };

-    const lib_dir_root = sdk.b.fmt("{s}/platforms/android-{d}", .{
+    const lib_dir = sdk.b.fmt("{s}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/{s}-linux-android/{}/",.{
         ndk_root,
+        @tagName(target),
         sdk.versions.android_sdk_version,
     });

-    const lib_dir = std.fs.path.resolve(sdk.b.allocator, &[_][]const u8{ lib_dir_root, config.lib_dir }) catch unreachable;
-
-    const prebuilt_dir = switch (builtin.os.tag) {
-        .windows => "windows",
-        .linux => "linux",
-        .macos => "darwin",
-        else => unreachable,
-    };
-
-    const libgcc_path = sdk.b.fmt(
-        "{s}/toolchains/{s}/prebuilt/{s}-x86_64/lib/gcc/{s}/4.9.x/libgcc.a",
-        .{ ndk_root, config.libgcc_dir, prebuilt_dir, config.include_dir },
-    );
+    //const prebuilt_dir = switch (builtin.os.tag) {
+    //    .windows => "windows",
+    //    .linux => "linux",
+    //    .macos => "darwin",
+    //    else => unreachable,
+    //};

     exe.setTarget(config.target);
     exe.addLibPath(lib_dir);
-    exe.addObjectFile(libgcc_path);
     exe.addIncludeDir(std.fs.path.resolve(sdk.b.allocator, &[_][]const u8{ include_dir, config.include_dir }) catch unreachable);

     exe.setLibCFile(sdk.createLibCFile(config.out_dir, include_dir, include_dir, lib_dir) catch unreachable);
diff --git a/build/auto-detect.zig b/build/auto-detect.zig
index 98bafce..2bfd5bc 100644
--- a/build/auto-detect.zig
+++ b/build/auto-detect.zig
@@ -458,6 +458,10 @@ fn findProblemWithAndroidNdk(b: *Builder, versions: Sdk.ToolchainVersions, path:

     const ndk_include_path = std.fs.path.join(b.allocator, &[_][]const u8{
         path,
+"toolchains",
+"llvm",
+"prebuilt",
+"linux-x86_64", //<host-tag>
         "sysroot",
         "usr",
         "include",

Improve the threading model for lifecycle events

Lifecycle events (onStart, onPause, onNativeWindowDestroyed, etc) come from threads that are disjoint from the main "background" thread, which runs independently. The way synchronization between these threads is done in the example is simply with a lock. This has two problems:

  1. If the lock is dropped and then taken again quickly by the main thread, waiting event threads may be starved out. Mutexes on Android are not "fair", and will not necessarily prioritize threads that have been waiting longer. This is unlikely to deadlock the application, but could cause a few extra frames of latency that are unnecessary.
  2. For calls like onNativeWindowDestroyed, it is important that the background thread does not continue to use the window after this function returns. This means that if the bg thread has access to the window, the event thread must pause and wait for the background thread to acknowledge the event before returning.

The "official" native app glue in the apk has a nicer model that might be worth taking a look at, where events are put into a queue and then the event thread waits for a signal from the background thread that the event has been processed. You can find it in ndk/sources/android/native_app_glue/android_native_app_glue.c (apache 2.0 licensed).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.