Skip to content
Merged
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
strategy:
matrix:
include:
- os: "ubuntu-22.04"
- os: "ubuntu-latest"
- os: "windows-latest"
- os: "macos-14" # arm64 as per table: https://github.com/actions/runner-images/blob/8a1eeaf6ac70c66f675a04078d1a7222edd42008/README.md#available-images

Expand Down Expand Up @@ -45,7 +45,7 @@ jobs:
# note(jae): 2024-09-15
# Uses download mirror first as preferred by Zig Foundation
# see: https://ziglang.org/news/migrate-to-self-hosting/
uses: mlugg/setup-zig@v1
uses: mlugg/setup-zig@v2
with:
version: "0.14.0"

Expand Down Expand Up @@ -99,7 +99,7 @@ jobs:
#

- name: Setup Zig Nightly
uses: mlugg/setup-zig@v1
uses: mlugg/setup-zig@v2
with:
version: "master"

Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ zig build -Dandroid=true
const android = @import("android");

pub fn build(b: *std.Build) !void {
const android_tools = android.Tools.create(b, ...);
const apk = android.APK.create(b, android_tools);
const android_sdk = android.Sdk.create(b, .{});
const apk = android_sdk.createApk(.{
.api_level = .android15,
.build_tools_version = "35.0.1",
.ndk_version = "29.0.13113456",
});
apk.setAndroidManifest(b.path("android/AndroidManifest.xml"));
apk.addResourceDirectory(b.path("android/res"));
apk.addJavaSourceFile(.{ .file = b.path("android/src/NativeInvocationHandler.java") });
Expand Down
26 changes: 16 additions & 10 deletions build.zig
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
const std = @import("std");
const androidbuild = @import("src/androidbuild/androidbuild.zig");
const Apk = @import("src/androidbuild/apk.zig");

// Expose Android build functionality for use in your build.zig

pub const Tools = @import("src/androidbuild/tools.zig");
pub const APK = Apk; // TODO(jae): 2025-03-13: Consider deprecating and using 'Apk' to be conventional to Zig
pub const APILevel = androidbuild.APILevel; // TODO(jae): 2025-03-13: Consider deprecating and using 'ApiLevel' to be conventional to Zig
// TODO: rename tools.zig to Sdk.zig
pub const Sdk = @import("src/androidbuild/tools.zig");
pub const Apk = @import("src/androidbuild/apk.zig");
pub const ApiLevel = androidbuild.ApiLevel;
pub const standardTargets = androidbuild.standardTargets;

// Deprecated exposes fields

/// Deprecated: Use Tools.Options instead.
pub const ToolsOptions = Tools.Options;
/// Deprecated: Use Tools.CreateKey instead.
pub const CreateKey = Tools.CreateKey;
// Deprecated exposed fields

/// Deprecated: Use ApiLevel
pub const APILevel = @compileError("use android.ApiLevel instead of android.APILevel");
/// Deprecated: Use Sdk instead
pub const Tools = @compileError("Use android.Sdk instead of android.Tools");
/// Deprecated: Use Apk.Options instead.
pub const ToolsOptions = @compileError("Use android.Sdk.Options instead of android.Apk.Options with the Sdk.createApk method");
/// Deprecated: Use Sdk.CreateKey instead.
pub const CreateKey = @compileError("Use android.Sdk.CreateKey instead of android.CreateKey. Change 'android_tools.createKeyStore(android.CreateKey.example())' to 'android_sdk.createKeyStore(.example)'");
/// Deprecated: Use Apk not APK
pub const APK = @compileError("Use android.Apk instead of android.APK");

/// NOTE: As well as providing the "android" module this declaration is required so this can be imported by other build.zig files
pub fn build(b: *std.Build) void {
Expand Down
9 changes: 8 additions & 1 deletion examples/minimal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

As of 2024-09-19, this is a thrown together, very quick copy-paste of the minimal example from the original [ZigAndroidTemplate](https://github.com/ikskuh/ZigAndroidTemplate/blob/master/examples/minimal/main.zig) repository.

### Build and run natively on your operating system or install/run on Android device

```sh
zig build run # Native
zig build run -Dandroid # Android
```

### Build, install to test one target against a local emulator and run

```sh
Expand All @@ -13,7 +20,7 @@ adb shell am start -S -W -n com.zig.minimal/android.app.NativeActivity
### Build and install for all supported Android targets

```sh
zig build -Dandroid=true
zig build -Dandroid
adb install ./zig-out/bin/minimal.apk
```

Expand Down
27 changes: 16 additions & 11 deletions examples/minimal/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,16 @@ pub fn build(b: *std.Build) void {
else
android_targets;

// If building with Android, initialize the tools / build
const android_apk: ?*android.APK = blk: {
if (android_targets.len == 0) {
break :blk null;
}
const android_tools = android.Tools.create(b, .{
const android_apk: ?*android.Apk = blk: {
if (android_targets.len == 0) break :blk null;

const android_sdk = android.Sdk.create(b, .{});
const apk = android_sdk.createApk(.{
.api_level = .android15,
.build_tools_version = "35.0.1",
.ndk_version = "29.0.13113456",
});
const apk = android.APK.create(b, android_tools);

const key_store_file = android_tools.createKeyStore(android.CreateKey.example());
const key_store_file = android_sdk.createKeyStore(.example);
apk.setKeyStore(key_store_file);
apk.setAndroidManifest(b.path("android/AndroidManifest.xml"));
apk.addResourceDirectory(b.path("android/res"));
Expand Down Expand Up @@ -62,7 +59,7 @@ pub fn build(b: *std.Build) void {
// NOTE: Android has different CPU targets so you need to build a version of your
// code for x86, x86_64, arm, arm64 and more
if (target.result.abi.isAndroid()) {
const apk: *android.APK = android_apk orelse @panic("Android APK should be initialized");
const apk: *android.Apk = android_apk orelse @panic("Android APK should be initialized");
const android_dep = b.dependency("android", .{
.optimize = optimize,
.target = target,
Expand All @@ -82,6 +79,14 @@ pub fn build(b: *std.Build) void {
}
}
if (android_apk) |apk| {
apk.installApk();
const installed_apk = apk.addInstallApk();
b.getInstallStep().dependOn(&installed_apk.step);

const android_sdk = apk.sdk;
const run_step = b.step("run", "Install and run the application on an Android device");
const adb_install = android_sdk.addAdbInstall(installed_apk.source);
const adb_start = android_sdk.addAdbStart("com.zig.minimal/android.app.NativeActivity");
adb_start.step.dependOn(&adb_install.step);
run_step.dependOn(&adb_start.step);
}
}
15 changes: 8 additions & 7 deletions examples/raylib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ ld.lld: warning: <path-to-project>/.zig-cache/o/4227869d730f094811a7cdaaab535797
```
You can ignore this error for now.

### Build and run natively on your operating system or install/run on Android device

```sh
zig build run # Native
zig build run -Dandroid # Android
```

### Build, install to test one target against a local emulator and run

```sh
Expand All @@ -18,16 +25,10 @@ adb shell am start -S -W -n com.zig.raylib/android.app.NativeActivity
### Build and install for all supported Android targets

```sh
zig build -Dandroid=true
zig build -Dandroid
adb install ./zig-out/bin/raylib.apk
```

### Build and run natively on your operating system

```sh
zig build run
```

### Uninstall your application

If installing your application fails with something like:
Expand Down
59 changes: 30 additions & 29 deletions examples/raylib/build.zig
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
const android = @import("android");
const std = @import("std");

//This is targeting android version 10 / API level 29.
//Change the value here and in android/AndroidManifest.xml to target your desired API level
const android_version: android.APILevel = .android10;
const android_api = std.fmt.comptimePrint("{}", .{@intFromEnum(android_version)});
const exe_name = "raylib";

pub fn build(b: *std.Build) void {
Expand All @@ -18,18 +14,17 @@ pub fn build(b: *std.Build) void {
else
android_targets;

const android_apk: ?*android.APK = blk: {
if (android_targets.len == 0) {
break :blk null;
}
const android_tools = android.Tools.create(b, .{
.api_level = android_version,
const android_apk: ?*android.Apk = blk: {
if (android_targets.len == 0) break :blk null;

const android_sdk = android.Sdk.create(b, .{});
const apk = android_sdk.createApk(.{
.api_level = .android10,
.build_tools_version = "35.0.1",
.ndk_version = "29.0.13113456",
});
const apk = android.APK.create(b, android_tools);

const key_store_file = android_tools.createKeyStore(android.CreateKey.example());
const key_store_file = android_sdk.createKeyStore(.example);
apk.setKeyStore(key_store_file);
apk.setAndroidManifest(b.path("android/AndroidManifest.xml"));
apk.addResourceDirectory(b.path("android/res"));
Expand All @@ -51,38 +46,36 @@ pub fn build(b: *std.Build) void {
lib.linkLibC();
b.installArtifact(lib);

const android_ndk_path = if(android_apk) |apk| (b.fmt("{s}/ndk/{s}", .{ apk.tools.android_sdk_path, apk.tools.ndk_version })) else "";
const raylib_dep = if (target.result.abi.isAndroid()) (
b.dependency("raylib_zig", .{
.target = target,
.optimize = optimize,
.android_api_version = @as([]const u8, android_api),
.android_ndk = @as([]const u8, android_ndk_path),
})) else (
const raylib_dep = if (android_apk) |apk|
b.dependency("raylib_zig", .{
.target = target,
.optimize = optimize,
.android_api_version = @as([]const u8, b.fmt("{}", .{@intFromEnum(apk.api_level)})),
.android_ndk = @as([]const u8, apk.ndk.path),
})
else
b.dependency("raylib_zig", .{
.target = target,
.optimize = optimize,
.shared = true
}));
.shared = true,
});

const raylib_artifact = raylib_dep.artifact("raylib");
lib.linkLibrary(raylib_artifact);
const raylib_mod = raylib_dep.module("raylib");
lib.root_module.addImport("raylib", raylib_mod);

if (target.result.abi.isAndroid()) {
const apk: *android.APK = android_apk orelse @panic("Android APK should be initialized");
if (android_apk) |apk| {
const android_dep = b.dependency("android", .{
.optimize = optimize,
.target = target,
});
lib.root_module.linkSystemLibrary("android", .{ .preferred_link_mode = .dynamic });
lib.root_module.addImport("android", android_dep.module("android"));
lib.root_module.linkSystemLibrary("android", .{});

const native_app_glue_dir: std.Build.LazyPath = .{ .cwd_relative = b.fmt("{s}/sources/android/native_app_glue", .{android_ndk_path}) };
const native_app_glue_dir: std.Build.LazyPath = .{ .cwd_relative = b.fmt("{s}/sources/android/native_app_glue", .{apk.ndk.path}) };
lib.root_module.addCSourceFile(.{ .file = native_app_glue_dir.path(b, "android_native_app_glue.c") });
lib.root_module.addIncludePath(native_app_glue_dir);

lib.root_module.linkSystemLibrary("log", .{ .preferred_link_mode = .dynamic });
apk.addArtifact(lib);
} else {
const exe = b.addExecutable(.{ .name = exe_name, .optimize = optimize, .root_module = lib_mod });
Expand All @@ -94,6 +87,14 @@ pub fn build(b: *std.Build) void {
}
}
if (android_apk) |apk| {
apk.installApk();
const installed_apk = apk.addInstallApk();
b.getInstallStep().dependOn(&installed_apk.step);

const android_sdk = apk.sdk;
const run_step = b.step("run", "Install and run the application on an Android device");
const adb_install = android_sdk.addAdbInstall(installed_apk.source);
const adb_start = android_sdk.addAdbStart("com.zig.raylib/android.app.NativeActivity");
adb_start.step.dependOn(&adb_install.step);
run_step.dependOn(&adb_start.step);
}
}
13 changes: 7 additions & 6 deletions examples/sdl2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

This is a copy-paste of [Andrew Kelly's SDL Zig Demo](https://github.com/andrewrk/sdl-zig-demo) but running on Android. The build is setup so you can also target your native operating system as well.

### Build and run natively on your operating system or install/run on Android device

```sh
zig build run # Native
zig build run -Dandroid # Android
```

### Build, install to test one target against a local emulator and run

```sh
Expand All @@ -17,12 +24,6 @@ zig build -Dandroid=true
adb install ./zig-out/bin/sdl-zig-demo.apk
```

### Build and run natively on your operating system

```sh
zig build run
```

### Uninstall your application

If installing your application fails with something like:
Expand Down
26 changes: 16 additions & 10 deletions examples/sdl2/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,11 @@ pub fn build(b: *std.Build) void {
else
android_targets;

// If building with Android, initialize the tools / build
const android_apk: ?*android.APK = blk: {
if (android_targets.len == 0) {
break :blk null;
}
const android_tools = android.Tools.create(b, .{
const android_apk: ?*android.Apk = blk: {
if (android_targets.len == 0) break :blk null;

const android_sdk = android.Sdk.create(b, .{});
const apk = android_sdk.createApk(.{
.api_level = .android15,
.build_tools_version = "35.0.1",
.ndk_version = "29.0.13113456",
Expand All @@ -34,9 +33,8 @@ pub fn build(b: *std.Build) void {
// - ndk/27.0.12077973/toolchains/llvm/prebuilt/{OS}-x86_64/sysroot/usr/include/android/hardware_buffer.h:322:42:
// - error: expression is not an integral constant expression
});
const apk = android.APK.create(b, android_tools);

const key_store_file = android_tools.createKeyStore(android.CreateKey.example());
const key_store_file = android_sdk.createKeyStore(.example);
apk.setKeyStore(key_store_file);
apk.setAndroidManifest(b.path("android/AndroidManifest.xml"));
apk.addResourceDirectory(b.path("android/res"));
Expand Down Expand Up @@ -113,7 +111,7 @@ pub fn build(b: *std.Build) void {
// NOTE: Android has different CPU targets so you need to build a version of your
// code for x86, x86_64, arm, arm64 and more
if (target.result.abi.isAndroid()) {
const apk: *android.APK = android_apk orelse @panic("Android APK should be initialized");
const apk: *android.Apk = android_apk orelse @panic("Android APK should be initialized");
const android_dep = b.dependency("android", .{
.optimize = optimize,
.target = target,
Expand All @@ -133,6 +131,14 @@ pub fn build(b: *std.Build) void {
}
}
if (android_apk) |apk| {
apk.installApk();
const installed_apk = apk.addInstallApk();
b.getInstallStep().dependOn(&installed_apk.step);

const android_sdk = apk.sdk;
const run_step = b.step("run", "Install and run the application on an Android device");
const adb_install = android_sdk.addAdbInstall(installed_apk.source);
const adb_start = android_sdk.addAdbStart("com.zig.sdl2/com.zig.sdl2.ZigSDLActivity");
adb_start.step.dependOn(&adb_install.step);
run_step.dependOn(&adb_start.step);
}
}
Loading