diff options
| author | ruki <[email protected]> | 2025-12-16 17:57:11 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-12-16 17:57:11 +0800 |
| commit | d1485fa867ebb3b661a16ec043f33537a7f9f0cd (patch) | |
| tree | 351a965dfb03438caf4a5a55620a11108ffabcac | |
| parent | d3acb6ca0d74d506d4a7da0fb7c055344591cb7a (diff) | |
| parent | 7b542ebe22e833bd56dd1eb0271aa5aa7c0b45a8 (diff) | |
Merge pull request #7139 from xmake-io/android
Add android native app support
39 files changed, 1145 insertions, 2 deletions
diff --git a/tests/projects/android/native_app/lvgl_basic/android/AndroidManifest.xml b/tests/projects/android/native_app/lvgl_basic/android/AndroidManifest.xml new file mode 100644 index 000000000..98c3d3795 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_basic/android/AndroidManifest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.lvgl.basic" + + android:versionCode="15" + android:versionName="1.5"> + + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" /> + + <uses-permission android:name="android.permission.SET_RELEASE_APP"/> + + <application + android:label="LvglBasic" android:debuggable="true" android:hasCode="false" + tools:replace="android:icon,android:theme,android:allowBackup,label" + android:icon="@mipmap/icon"> + + <activity android:name="android.app.NativeActivity" + android:label="LvglBasic" + android:configChanges="orientation|keyboardHidden|screenSize|screenLayout" + android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> + <meta-data android:name="android.app.lib_name" + android:value="main" /> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest>
\ No newline at end of file diff --git a/tests/projects/android/native_app/lvgl_basic/android/debug.jks b/tests/projects/android/native_app/lvgl_basic/android/debug.jks Binary files differnew file mode 100644 index 000000000..0a18aa012 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_basic/android/debug.jks diff --git a/tests/projects/android/native_app/lvgl_basic/android/res/mipmap-mdpi/icon.png b/tests/projects/android/native_app/lvgl_basic/android/res/mipmap-mdpi/icon.png Binary files differnew file mode 100644 index 000000000..743413831 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_basic/android/res/mipmap-mdpi/icon.png diff --git a/tests/projects/android/native_app/lvgl_basic/android/res/mipmap/icon.png b/tests/projects/android/native_app/lvgl_basic/android/res/mipmap/icon.png Binary files differnew file mode 100644 index 000000000..743413831 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_basic/android/res/mipmap/icon.png diff --git a/tests/projects/android/native_app/lvgl_basic/android/res/values/strings.xml b/tests/projects/android/native_app/lvgl_basic/android/res/values/strings.xml new file mode 100644 index 000000000..7dc865540 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_basic/android/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">Lvgl Basic</string> +</resources>
\ No newline at end of file diff --git a/tests/projects/android/native_app/lvgl_basic/android/res/values/styles.xml b/tests/projects/android/native_app/lvgl_basic/android/res/values/styles.xml new file mode 100644 index 000000000..621547380 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_basic/android/res/values/styles.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="AppTheme" parent="android:Theme.NoTitleBar.Fullscreen"> + <item name="android:windowBackground">@android:color/black</item> + <item name="android:colorPrimary">#FF6200EE</item> + <item name="android:colorPrimaryDark">#FF3700B3</item> + <item name="android:colorAccent">#FF03DAC5</item> + </style> +</resources>
\ No newline at end of file diff --git a/tests/projects/android/native_app/lvgl_basic/src/main.c b/tests/projects/android/native_app/lvgl_basic/src/main.c new file mode 100644 index 000000000..f07036e9b --- /dev/null +++ b/tests/projects/android/native_app/lvgl_basic/src/main.c @@ -0,0 +1,169 @@ +#include <lvgl/lvgl.h> +#include <android/native_window.h> +#include <android/log.h> +#include <android_native_app_glue.h> +#include <time.h> +#include <stdlib.h> +#include <unistd.h> + +#define LOG_TAG "lvgl_basic" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) + +static lv_display_t * display = NULL; +static lv_indev_t * indev = NULL; +static void * disp_buf = NULL; +static ANativeWindow * native_window = NULL; +static int32_t window_width = 0; +static int32_t window_height = 0; +static lv_obj_t * label_fps = NULL; + +static bool touch_down = false; +static int32_t touch_x = 0; +static int32_t touch_y = 0; + +static void my_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map) { + if (!native_window) { + lv_display_flush_ready(disp); + return; + } + + ANativeWindow_Buffer buffer; + if (ANativeWindow_lock(native_window, &buffer, NULL) < 0) { + lv_display_flush_ready(disp); + return; + } + + int32_t width = lv_area_get_width(area); + int32_t height = lv_area_get_height(area); + + // Assume 32-bit RGBA + uint32_t * dst_base = (uint32_t *)buffer.bits; + uint32_t * src = (uint32_t *)px_map; + int stride = buffer.stride; + + for (int y = 0; y < height; y++) { + uint32_t * dst_line = dst_base + (area->y1 + y) * stride + area->x1; + memcpy(dst_line, src + y * width, width * sizeof(uint32_t)); + } + + ANativeWindow_unlockAndPost(native_window); + lv_display_flush_ready(disp); +} + +static void my_input_read(lv_indev_t * indev, lv_indev_data_t * data) { + data->point.x = touch_x; + data->point.y = touch_y; + data->state = touch_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; +} + +static void create_ui(void) { + lv_obj_t * label = lv_label_create(lv_screen_active()); + lv_label_set_text(label, "Hello Xmake + LVGL!"); + lv_obj_set_style_text_font(label, &lv_font_montserrat_14, 0); + lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 50); + + // FPS label + label_fps = lv_label_create(lv_screen_active()); + lv_label_set_text(label_fps, "FPS: 0"); + lv_obj_set_style_text_font(label_fps, &lv_font_montserrat_14, 0); + lv_obj_align(label_fps, LV_ALIGN_TOP_MID, 0, 100); +} + +static void handle_cmd(struct android_app* app, int32_t cmd) { + switch (cmd) { + case APP_CMD_INIT_WINDOW: + LOGI("Init Window"); + native_window = app->window; + window_width = ANativeWindow_getWidth(native_window); + window_height = ANativeWindow_getHeight(native_window); + ANativeWindow_setBuffersGeometry(native_window, window_width, window_height, WINDOW_FORMAT_RGBA_8888); + + if (!display) { + display = lv_display_create(window_width, window_height); + lv_display_set_color_format(display, LV_COLOR_FORMAT_ARGB8888); + lv_display_set_flush_cb(display, my_flush_cb); + + size_t buf_size = window_width * window_height * 4; + disp_buf = malloc(buf_size); + lv_display_set_buffers(display, disp_buf, NULL, buf_size, LV_DISPLAY_RENDER_MODE_FULL); + + indev = lv_indev_create(); + lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); + lv_indev_set_read_cb(indev, my_input_read); + + create_ui(); + } else { + lv_display_set_resolution(display, window_width, window_height); + lv_obj_invalidate(lv_scr_act()); + } + break; + case APP_CMD_TERM_WINDOW: + native_window = NULL; + break; + case APP_CMD_DESTROY: + if (display) { + lv_display_delete(display); + display = NULL; + } + if (indev) { + lv_indev_delete(indev); + indev = NULL; + } + if (disp_buf) { + free(disp_buf); + disp_buf = NULL; + } + break; + } +} + +static int32_t handle_input(struct android_app* app, AInputEvent* event) { + if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { + int action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK; + touch_x = AMotionEvent_getX(event, 0); + touch_y = AMotionEvent_getY(event, 0); + if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE) { + touch_down = true; + } else { + touch_down = false; + } + return 1; + } + return 0; +} + +void android_main(struct android_app* app) { + lv_init(); + + app->onAppCmd = handle_cmd; + app->onInputEvent = handle_input; + + int frame_count = 0; + time_t last_time = time(NULL); + + while (1) { + int ident; + int events; + struct android_poll_source* source; + + uint32_t timeout = lv_timer_handler(); + if (timeout > 50) timeout = 50; + + while ((ident = ALooper_pollAll(timeout, NULL, &events, (void**)&source)) >= 0) { + if (source != NULL) source->process(app, source); + if (app->destroyRequested != 0) return; + } + + lv_tick_inc(timeout); + + frame_count++; + time_t current_time = time(NULL); + if (current_time - last_time >= 1) { + if (label_fps) { + lv_label_set_text_fmt(label_fps, "FPS: %d", frame_count); + } + frame_count = 0; + last_time = current_time; + } + } +} diff --git a/tests/projects/android/native_app/lvgl_basic/xmake.lua b/tests/projects/android/native_app/lvgl_basic/xmake.lua new file mode 100644 index 000000000..659d04f45 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_basic/xmake.lua @@ -0,0 +1,23 @@ +add_rules("mode.debug", "mode.release") + +add_requires("lvgl 9.1.0") + +target("lvgl_basic") + set_kind("binary") + set_languages("c99") + add_files("src/main.c") + add_syslinks("log", "android", "EGL", "GLESv2") + add_packages("lvgl") + + -- define LV_CONF_INCLUDE_SIMPLE to include lv_conf.h + add_defines("LV_CONF_INCLUDE_SIMPLE") + + add_rules("android.native_app", { + android_sdk_version = "35", + android_manifest = "android/AndroidManifest.xml", + android_res = "android/res", + keystore = "android/debug.jks", + keystore_pass = "123456", + package_name = "com.lvgl.basic", + logcat_filters = {"lvgl_basic", "lvgl"} + }) diff --git a/tests/projects/android/native_app/lvgl_particles/android/AndroidManifest.xml b/tests/projects/android/native_app/lvgl_particles/android/AndroidManifest.xml new file mode 100644 index 000000000..16d614e95 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_particles/android/AndroidManifest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.lvgl.particles" + + android:versionCode="15" + android:versionName="1.5"> + + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" /> + + <uses-permission android:name="android.permission.SET_RELEASE_APP"/> + + <application + android:label="LvglParticles" android:debuggable="true" android:hasCode="false" + tools:replace="android:icon,android:theme,android:allowBackup,label" + android:icon="@mipmap/icon"> + + <activity android:name="android.app.NativeActivity" + android:label="LvglParticles" + android:configChanges="orientation|keyboardHidden|screenSize|screenLayout" + android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> + <meta-data android:name="android.app.lib_name" + android:value="main" /> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest>
\ No newline at end of file diff --git a/tests/projects/android/native_app/lvgl_particles/android/debug.jks b/tests/projects/android/native_app/lvgl_particles/android/debug.jks Binary files differnew file mode 100644 index 000000000..0a18aa012 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_particles/android/debug.jks diff --git a/tests/projects/android/native_app/lvgl_particles/android/res/mipmap-mdpi/icon.png b/tests/projects/android/native_app/lvgl_particles/android/res/mipmap-mdpi/icon.png Binary files differnew file mode 100644 index 000000000..743413831 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_particles/android/res/mipmap-mdpi/icon.png diff --git a/tests/projects/android/native_app/lvgl_particles/android/res/mipmap/icon.png b/tests/projects/android/native_app/lvgl_particles/android/res/mipmap/icon.png Binary files differnew file mode 100644 index 000000000..743413831 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_particles/android/res/mipmap/icon.png diff --git a/tests/projects/android/native_app/lvgl_particles/android/res/values/strings.xml b/tests/projects/android/native_app/lvgl_particles/android/res/values/strings.xml new file mode 100644 index 000000000..0c86996ef --- /dev/null +++ b/tests/projects/android/native_app/lvgl_particles/android/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">Lvgl Particles</string> +</resources>
\ No newline at end of file diff --git a/tests/projects/android/native_app/lvgl_particles/android/res/values/styles.xml b/tests/projects/android/native_app/lvgl_particles/android/res/values/styles.xml new file mode 100644 index 000000000..621547380 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_particles/android/res/values/styles.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="AppTheme" parent="android:Theme.NoTitleBar.Fullscreen"> + <item name="android:windowBackground">@android:color/black</item> + <item name="android:colorPrimary">#FF6200EE</item> + <item name="android:colorPrimaryDark">#FF3700B3</item> + <item name="android:colorAccent">#FF03DAC5</item> + </style> +</resources>
\ No newline at end of file diff --git a/tests/projects/android/native_app/lvgl_particles/src/main.c b/tests/projects/android/native_app/lvgl_particles/src/main.c new file mode 100644 index 000000000..1db849fc1 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_particles/src/main.c @@ -0,0 +1,261 @@ +#include <lvgl/lvgl.h> +#include <android/native_window.h> +#include <android/log.h> +#include <android_native_app_glue.h> +#include <time.h> +#include <stdlib.h> +#include <unistd.h> + +#define LOG_TAG "lvgl_particles" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) + +static lv_display_t * display = NULL; +static lv_indev_t * indev = NULL; +static void * disp_buf = NULL; +static ANativeWindow * native_window = NULL; +static int32_t window_width = 0; +static int32_t window_height = 0; +static lv_obj_t * label_fps = NULL; + +static bool touch_down = false; +static int32_t touch_x = 0; +static int32_t touch_y = 0; + +static void my_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map) { + if (!native_window) { + lv_display_flush_ready(disp); + return; + } + + ANativeWindow_Buffer buffer; + if (ANativeWindow_lock(native_window, &buffer, NULL) < 0) { + lv_display_flush_ready(disp); + return; + } + + int32_t width = lv_area_get_width(area); + int32_t height = lv_area_get_height(area); + + // Assume 32-bit RGBA + uint32_t * dst_base = (uint32_t *)buffer.bits; + uint32_t * src = (uint32_t *)px_map; + int stride = buffer.stride; + + for (int y = 0; y < height; y++) { + uint32_t * dst_line = dst_base + (area->y1 + y) * stride + area->x1; + memcpy(dst_line, src + y * width, width * sizeof(uint32_t)); + } + + ANativeWindow_unlockAndPost(native_window); + lv_display_flush_ready(disp); +} + +static void my_input_read(lv_indev_t * indev, lv_indev_data_t * data) { + data->point.x = touch_x; + data->point.y = touch_y; + data->state = touch_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; +} + +#include <math.h> + +typedef struct { + int32_t x; + int32_t y; + int32_t vx; + int32_t vy; + lv_color_t color; + int32_t size; + int32_t life; +} Particle; + +#define MAX_PARTICLES 100 +static Particle particles[MAX_PARTICLES]; +static int particle_count = 0; + +static void create_particle(int32_t x, int32_t y) { + if (particle_count < MAX_PARTICLES) { + Particle *p = &particles[particle_count++]; + p->x = x; + p->y = y; + p->vx = (rand() % 10) - 5; + p->vy = (rand() % 10) - 5; + p->color = lv_color_make(rand() % 255, rand() % 255, rand() % 255); + p->size = (rand() % 15) + 5; + p->life = 100; + } +} + +static void update_particles(void) { + for (int i = 0; i < particle_count; i++) { + Particle *p = &particles[i]; + p->x += p->vx; + p->y += p->vy; + p->life--; + + if (p->life <= 0 || p->x < 0 || p->x > window_width || p->y < 0 || p->y > window_height) { + *p = particles[--particle_count]; + i--; + } + } +} + +static void draw_particles(lv_layer_t * layer) { + lv_draw_rect_dsc_t draw_dsc; + lv_draw_rect_dsc_init(&draw_dsc); + draw_dsc.radius = LV_RADIUS_CIRCLE; + + for (int i = 0; i < particle_count; i++) { + Particle *p = &particles[i]; + draw_dsc.bg_color = p->color; + draw_dsc.bg_opa = (p->life * 255) / 100; + + lv_area_t area; + area.x1 = p->x - p->size / 2; + area.y1 = p->y - p->size / 2; + area.x2 = area.x1 + p->size; + area.y2 = area.y1 + p->size; + + lv_draw_rect(layer, &draw_dsc, &area); + } +} + +static void particle_timer_cb(lv_timer_t * timer) { + if (touch_down) { + for (int i = 0; i < 5; i++) { + create_particle(touch_x, touch_y); + } + } else { + // Auto emit + static float t = 0; + t += 0.1f; + int cx = window_width / 2 + cos(t) * (window_width / 4); + int cy = window_height / 2 + sin(t) * (window_height / 4); + create_particle(cx, cy); + } + + update_particles(); + lv_obj_invalidate(lv_scr_act()); // Force redraw +} + +static void canvas_draw_event_cb(lv_event_t * e) { + lv_layer_t * layer = lv_event_get_layer(e); + draw_particles(layer); +} + +static void create_ui(void) { + lv_obj_t * label = lv_label_create(lv_screen_active()); + lv_label_set_text(label, "Touch to create particles!"); + lv_obj_set_style_text_font(label, &lv_font_montserrat_14, 0); + lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 50); + + // FPS label + label_fps = lv_label_create(lv_screen_active()); + lv_label_set_text(label_fps, "FPS: 0"); + lv_obj_set_style_text_font(label_fps, &lv_font_montserrat_14, 0); + lv_obj_align(label_fps, LV_ALIGN_TOP_MID, 0, 100); + + // Add draw event to screen for particles + lv_obj_add_event_cb(lv_screen_active(), canvas_draw_event_cb, LV_EVENT_DRAW_POST, NULL); + + lv_timer_create(particle_timer_cb, 16, NULL); +} + +static void handle_cmd(struct android_app* app, int32_t cmd) { + switch (cmd) { + case APP_CMD_INIT_WINDOW: + LOGI("Init Window"); + native_window = app->window; + window_width = ANativeWindow_getWidth(native_window); + window_height = ANativeWindow_getHeight(native_window); + ANativeWindow_setBuffersGeometry(native_window, window_width, window_height, WINDOW_FORMAT_RGBA_8888); + + if (!display) { + display = lv_display_create(window_width, window_height); + lv_display_set_color_format(display, LV_COLOR_FORMAT_ARGB8888); + lv_display_set_flush_cb(display, my_flush_cb); + + size_t buf_size = window_width * window_height * 4; + disp_buf = malloc(buf_size); + lv_display_set_buffers(display, disp_buf, NULL, buf_size, LV_DISPLAY_RENDER_MODE_FULL); + + indev = lv_indev_create(); + lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); + lv_indev_set_read_cb(indev, my_input_read); + + create_ui(); + } else { + lv_display_set_resolution(display, window_width, window_height); + lv_obj_invalidate(lv_scr_act()); + } + break; + case APP_CMD_TERM_WINDOW: + native_window = NULL; + break; + case APP_CMD_DESTROY: + if (display) { + lv_display_delete(display); + display = NULL; + } + if (indev) { + lv_indev_delete(indev); + indev = NULL; + } + if (disp_buf) { + free(disp_buf); + disp_buf = NULL; + } + break; + } +} + +static int32_t handle_input(struct android_app* app, AInputEvent* event) { + if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { + int action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK; + touch_x = AMotionEvent_getX(event, 0); + touch_y = AMotionEvent_getY(event, 0); + if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE) { + touch_down = true; + } else { + touch_down = false; + } + return 1; + } + return 0; +} + +void android_main(struct android_app* app) { + srand(time(NULL)); + lv_init(); + + app->onAppCmd = handle_cmd; + app->onInputEvent = handle_input; + + int frame_count = 0; + time_t last_time = time(NULL); + + while (1) { + int ident; + int events; + struct android_poll_source* source; + + uint32_t timeout = lv_timer_handler(); + if (timeout > 50) timeout = 50; + + while ((ident = ALooper_pollAll(timeout, NULL, &events, (void**)&source)) >= 0) { + if (source != NULL) source->process(app, source); + if (app->destroyRequested != 0) return; + } + + lv_tick_inc(timeout); + + frame_count++; + time_t current_time = time(NULL); + if (current_time - last_time >= 1) { + if (label_fps) { + lv_label_set_text_fmt(label_fps, "FPS: %d", frame_count); + } + frame_count = 0; + last_time = current_time; + } + } +} diff --git a/tests/projects/android/native_app/lvgl_particles/xmake.lua b/tests/projects/android/native_app/lvgl_particles/xmake.lua new file mode 100644 index 000000000..3a74e8439 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_particles/xmake.lua @@ -0,0 +1,23 @@ +add_rules("mode.debug", "mode.release") + +add_requires("lvgl 9.1.0") + +target("lvgl_particles") + set_kind("binary") + set_languages("c99") + add_files("src/main.c") + add_syslinks("log", "android", "EGL", "GLESv2") + add_packages("lvgl") + + -- define LV_CONF_INCLUDE_SIMPLE to include lv_conf.h + add_defines("LV_CONF_INCLUDE_SIMPLE") + + add_rules("android.native_app", { + android_sdk_version = "35", + android_manifest = "android/AndroidManifest.xml", + android_res = "android/res", + keystore = "android/debug.jks", + keystore_pass = "123456", + package_name = "com.lvgl.particles", + logcat_filters = {"lvgl_particles", "lvgl"} + }) diff --git a/tests/projects/android/native_app/raylib_basic/android/AndroidManifest.xml b/tests/projects/android/native_app/raylib_basic/android/AndroidManifest.xml new file mode 100644 index 000000000..2d6b2d67c --- /dev/null +++ b/tests/projects/android/native_app/raylib_basic/android/AndroidManifest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.raylib.basic" + + android:versionCode="15" + android:versionName="1.5"> + + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" /> + + <uses-permission android:name="android.permission.SET_RELEASE_APP"/> + + <application + android:label="RaylibBasic" android:debuggable="true" android:hasCode="false" + tools:replace="android:icon,android:theme,android:allowBackup,label" + android:icon="@mipmap/icon"> + + <activity android:name="android.app.NativeActivity" + android:label="RaylibBasic" + android:configChanges="orientation|keyboardHidden|screenSize|screenLayout" + android:screenOrientation="portrait" + android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> + <meta-data android:name="android.app.lib_name" + android:value="main" /> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest>
\ No newline at end of file diff --git a/tests/projects/android/native_app/raylib_basic/android/debug.jks b/tests/projects/android/native_app/raylib_basic/android/debug.jks Binary files differnew file mode 100644 index 000000000..0a18aa012 --- /dev/null +++ b/tests/projects/android/native_app/raylib_basic/android/debug.jks diff --git a/tests/projects/android/native_app/raylib_basic/android/res/mipmap-mdpi/icon.png b/tests/projects/android/native_app/raylib_basic/android/res/mipmap-mdpi/icon.png Binary files differnew file mode 100644 index 000000000..743413831 --- /dev/null +++ b/tests/projects/android/native_app/raylib_basic/android/res/mipmap-mdpi/icon.png diff --git a/tests/projects/android/native_app/raylib_basic/android/res/mipmap/icon.png b/tests/projects/android/native_app/raylib_basic/android/res/mipmap/icon.png Binary files differnew file mode 100644 index 000000000..743413831 --- /dev/null +++ b/tests/projects/android/native_app/raylib_basic/android/res/mipmap/icon.png diff --git a/tests/projects/android/native_app/raylib_basic/android/res/values/strings.xml b/tests/projects/android/native_app/raylib_basic/android/res/values/strings.xml new file mode 100644 index 000000000..bc0a9bfbf --- /dev/null +++ b/tests/projects/android/native_app/raylib_basic/android/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">Raylib Basic</string> +</resources>
\ No newline at end of file diff --git a/tests/projects/android/native_app/raylib_basic/android/res/values/styles.xml b/tests/projects/android/native_app/raylib_basic/android/res/values/styles.xml new file mode 100644 index 000000000..621547380 --- /dev/null +++ b/tests/projects/android/native_app/raylib_basic/android/res/values/styles.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="AppTheme" parent="android:Theme.NoTitleBar.Fullscreen"> + <item name="android:windowBackground">@android:color/black</item> + <item name="android:colorPrimary">#FF6200EE</item> + <item name="android:colorPrimaryDark">#FF3700B3</item> + <item name="android:colorAccent">#FF03DAC5</item> + </style> +</resources>
\ No newline at end of file diff --git a/tests/projects/android/native_app/raylib_basic/src/main.cpp b/tests/projects/android/native_app/raylib_basic/src/main.cpp new file mode 100644 index 000000000..0094d9e3c --- /dev/null +++ b/tests/projects/android/native_app/raylib_basic/src/main.cpp @@ -0,0 +1,32 @@ +#include <raylib.h> +#include <android/log.h> + +#define LOG_TAG "raydemo_basic" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) + +int main(int argc, char** argv) { + InitWindow(0, 0, "Hello, xmake for raylib android!"); + SetTargetFPS(60); + LOGI("raylib application is running!"); + + while (!WindowShouldClose()) { + BeginDrawing(); + ClearBackground(BLACK); + + // Draw FPS + const char* fpsText = TextFormat("%2i FPS", GetFPS()); + int fpsWidth = MeasureText(fpsText, 40); + DrawText(fpsText, GetScreenWidth() / 2 - fpsWidth / 2, 30, 40, GREEN); + + // Draw centered text + int fontSize = 50; + const char* text = "Hello, xmake for raylib android!"; + int textWidth = MeasureText(text, fontSize); + DrawText(text, GetScreenWidth() / 2 - textWidth / 2, 100, fontSize, BLUE); + + EndDrawing(); + } + + CloseWindow(); + return 0; +} diff --git a/tests/projects/android/native_app/raylib_basic/xmake.lua b/tests/projects/android/native_app/raylib_basic/xmake.lua new file mode 100644 index 000000000..50886764d --- /dev/null +++ b/tests/projects/android/native_app/raylib_basic/xmake.lua @@ -0,0 +1,19 @@ +add_rules("mode.debug", "mode.release") + +add_requires("raylib 5.5.0") + +target("raydemo_basic") + set_kind("binary") + set_languages("c++17") + add_files("src/main.cpp") + add_syslinks("log") + add_packages("raylib") + add_rules("android.native_app", { + android_sdk_version = "35", + android_manifest = "android/AndroidManifest.xml", + android_res = "android/res", + keystore = "android/debug.jks", + keystore_pass = "123456", + package_name = "com.raylib.basic", + logcat_filters = {"raydemo_basic", "raylib"} + }) diff --git a/tests/projects/android/native_app/raylib_particles/android/AndroidManifest.xml b/tests/projects/android/native_app/raylib_particles/android/AndroidManifest.xml new file mode 100644 index 000000000..70dd36933 --- /dev/null +++ b/tests/projects/android/native_app/raylib_particles/android/AndroidManifest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.raylib.particles" + + android:versionCode="15" + android:versionName="1.5"> + + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" /> + + <uses-permission android:name="android.permission.SET_RELEASE_APP"/> + + <application + android:label="RaylibParticles" android:debuggable="true" android:hasCode="false" + tools:replace="android:icon,android:theme,android:allowBackup,label" + android:icon="@mipmap/icon"> + + <activity android:name="android.app.NativeActivity" + android:label="RaylibParticles" + android:configChanges="orientation|keyboardHidden|screenSize|screenLayout" + android:screenOrientation="portrait" + android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> + <meta-data android:name="android.app.lib_name" + android:value="main" /> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest>
\ No newline at end of file diff --git a/tests/projects/android/native_app/raylib_particles/android/debug.jks b/tests/projects/android/native_app/raylib_particles/android/debug.jks Binary files differnew file mode 100644 index 000000000..0a18aa012 --- /dev/null +++ b/tests/projects/android/native_app/raylib_particles/android/debug.jks diff --git a/tests/projects/android/native_app/raylib_particles/android/res/mipmap-mdpi/icon.png b/tests/projects/android/native_app/raylib_particles/android/res/mipmap-mdpi/icon.png Binary files differnew file mode 100644 index 000000000..743413831 --- /dev/null +++ b/tests/projects/android/native_app/raylib_particles/android/res/mipmap-mdpi/icon.png diff --git a/tests/projects/android/native_app/raylib_particles/android/res/mipmap/icon.png b/tests/projects/android/native_app/raylib_particles/android/res/mipmap/icon.png Binary files differnew file mode 100644 index 000000000..743413831 --- /dev/null +++ b/tests/projects/android/native_app/raylib_particles/android/res/mipmap/icon.png diff --git a/tests/projects/android/native_app/raylib_particles/android/res/values/strings.xml b/tests/projects/android/native_app/raylib_particles/android/res/values/strings.xml new file mode 100644 index 000000000..3967cc312 --- /dev/null +++ b/tests/projects/android/native_app/raylib_particles/android/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">Raylib Particles</string> +</resources>
\ No newline at end of file diff --git a/tests/projects/android/native_app/raylib_particles/android/res/values/styles.xml b/tests/projects/android/native_app/raylib_particles/android/res/values/styles.xml new file mode 100644 index 000000000..621547380 --- /dev/null +++ b/tests/projects/android/native_app/raylib_particles/android/res/values/styles.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="AppTheme" parent="android:Theme.NoTitleBar.Fullscreen"> + <item name="android:windowBackground">@android:color/black</item> + <item name="android:colorPrimary">#FF6200EE</item> + <item name="android:colorPrimaryDark">#FF3700B3</item> + <item name="android:colorAccent">#FF03DAC5</item> + </style> +</resources>
\ No newline at end of file diff --git a/tests/projects/android/native_app/raylib_particles/src/main.cpp b/tests/projects/android/native_app/raylib_particles/src/main.cpp new file mode 100644 index 000000000..5bbfc90e8 --- /dev/null +++ b/tests/projects/android/native_app/raylib_particles/src/main.cpp @@ -0,0 +1,89 @@ +#include <raylib.h> +#include <android/log.h> +#include <vector> +#include <cmath> + +#define LOG_TAG "raydemo_particles" +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) + +struct Particle { + Vector2 position; + Vector2 velocity; + Color color; + float size; + float life; +}; + +int main(int argc, char** argv) { + InitWindow(0, 0, "Raylib Particles"); + SetTargetFPS(60); + LOGD("raylib particles starting!"); + + std::vector<Particle> particles; + + while (!WindowShouldClose()) { + // Update + bool inputActive = IsMouseButtonDown(MOUSE_BUTTON_LEFT) || GetTouchPointCount() > 0; + Vector2 pos; + + if (inputActive) { + pos = GetMousePosition(); + if (GetTouchPointCount() > 0) pos = GetTouchPosition(0); + } else { + // Auto emit when idle + double time = GetTime(); + pos.x = GetScreenWidth() / 2.0f + cos(time * 3.0f) * (GetScreenWidth() / 4.0f); + pos.y = GetScreenHeight() / 2.0f + sin(time * 2.0f) * (GetScreenHeight() / 4.0f); + } + + if (inputActive || GetRandomValue(0, 100) < 50) { + int count = inputActive ? 5 : 2; + for (int i = 0; i < count; i++) { + Particle p; + p.position = pos; + p.velocity = {(float)GetRandomValue(-200, 200) / 100.0f, (float)GetRandomValue(-200, 200) / 100.0f}; + p.color = (Color){(unsigned char)GetRandomValue(0, 255), (unsigned char)GetRandomValue(0, 255), (unsigned char)GetRandomValue(0, 255), 255}; + p.size = (float)GetRandomValue(5, 20); + p.life = 1.0f; + particles.push_back(p); + } + } + + for (auto it = particles.begin(); it != particles.end();) { + it->position.x += it->velocity.x * 5.0f; + it->position.y += it->velocity.y * 5.0f; + it->life -= 0.02f; + it->size *= 0.99f; + + if (it->life <= 0) { + it = particles.erase(it); + } else { + ++it; + } + } + + // Draw + BeginDrawing(); + ClearBackground(BLACK); + + for (const auto& p : particles) { + DrawCircleV(p.position, p.size, Fade(p.color, p.life)); + } + + // Draw FPS + const char* fpsText = TextFormat("%2i FPS", GetFPS()); + int fpsWidth = MeasureText(fpsText, 40); + DrawText(fpsText, GetScreenWidth() / 2 - fpsWidth / 2, 30, 40, GREEN); + + // Draw centered instructions + int fontSize = 40; + const char* text = "Touch to create particles!"; + int textWidth = MeasureText(text, fontSize); + DrawText(text, GetScreenWidth() / 2 - textWidth / 2, 80, fontSize, WHITE); + + EndDrawing(); + } + + CloseWindow(); + return 0; +} diff --git a/tests/projects/android/native_app/raylib_particles/xmake.lua b/tests/projects/android/native_app/raylib_particles/xmake.lua new file mode 100644 index 000000000..c6d9a6217 --- /dev/null +++ b/tests/projects/android/native_app/raylib_particles/xmake.lua @@ -0,0 +1,19 @@ +add_rules("mode.debug", "mode.release") + +add_requires("raylib 5.5.0") + +target("raydemo_particles") + set_kind("binary") + set_languages("c++17") + add_files("src/main.cpp") + add_syslinks("log") + add_packages("raylib") + add_rules("android.native_app", { + android_sdk_version = "35", + android_manifest = "android/AndroidManifest.xml", + android_res = "android/res", + keystore = "android/debug.jks", + keystore_pass = "123456", + package_name = "com.raylib.particles", + logcat_filters = {"raydemo_particles", "raylib"} + }) diff --git a/xmake/actions/run/main.lua b/xmake/actions/run/main.lua index 94c7d7d6b..6cfe09d3a 100644 --- a/xmake/actions/run/main.lua +++ b/xmake/actions/run/main.lua @@ -145,6 +145,18 @@ function _run(target) os.setenvs(oldenvs) end +-- check if the target is runnable +function _is_runnable(target) + if target:is_binary() or target:script("run") then + return true + end + for _, r in ipairs(target:orderules()) do + if r:script("run") then + return true + end + end +end + -- check targets function _check_targets(targetname, group_pattern) @@ -155,7 +167,7 @@ function _check_targets(targetname, group_pattern) table.insert(targets, target) else for _, target in ipairs(project.ordertargets()) do - if target:is_binary() or target:script("run") then + if _is_runnable(target) then local group = target:get("group") if (target:is_default() and not group_pattern) or option.get("all") or (group_pattern and group and group:match(group_pattern)) then table.insert(targets, target) @@ -216,7 +228,7 @@ function main() else local targets = {} for _, target in ipairs(project.ordertargets()) do - if target:is_binary() or target:script("run") then + if _is_runnable(target) then local group = target:get("group") if (target:is_default() and not group_pattern) or option.get("all") or (group_pattern and group and group:match(group_pattern)) then table.insert(targets, target) diff --git a/xmake/rules/platform/android/install.lua b/xmake/rules/platform/android/install.lua new file mode 100644 index 000000000..ec340ac00 --- /dev/null +++ b/xmake/rules/platform/android/install.lua @@ -0,0 +1,34 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author keosu +-- @file install.lua +-- + +-- imports + +function main(target) + + local android_sdkdir = target:toolchain("ndk"):config("android_sdk") + local adb = path.join(android_sdkdir, "platform-tools", "adb") + + local final_apk = path.join(target:targetdir(), target:basename() .. ".apk") + assert(os.isfile(final_apk), "apk file %s not found!", final_apk) + + cprint("installing %s ...", final_apk) + os.vrunv(adb, {"install", "-r", final_apk}) + cprint("install ok") +end diff --git a/xmake/rules/platform/android/load.lua b/xmake/rules/platform/android/load.lua new file mode 100644 index 000000000..3e49d9533 --- /dev/null +++ b/xmake/rules/platform/android/load.lua @@ -0,0 +1,44 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author keosu +-- @file load.lua +-- + +function main(target) + + -- only for android target + if not target:is_plat("android") then + wprint("rule(android.native_app): only for android system!") + target:rule_enable("android.native_app", false) + return + end + + local toolchain_ndk = target:toolchain("ndk") + local ndk_root = toolchain_ndk:config("ndk") + if not ndk_root then + raise("NDK path not set! Please set NDK path properly.") + end + + -- set target kind + target:set("kind", "shared") + + -- add glue file to target + local native_app_glue_file = path.join(ndk_root, "sources", "android", "native_app_glue", "android_native_app_glue.c") + local native_app_glue_dir = path.directory(native_app_glue_file) + target:add("files", native_app_glue_file) + target:add("includedirs", native_app_glue_dir) +end diff --git a/xmake/rules/platform/android/package.lua b/xmake/rules/platform/android/package.lua new file mode 100644 index 000000000..00142a85f --- /dev/null +++ b/xmake/rules/platform/android/package.lua @@ -0,0 +1,103 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author keosu +-- @file package.lua +-- + +-- imports +import("core.project.depend") +import("utils.progress") + +function main(target, opt) + + local conf = target:extraconf("rules", "android.native_app") + local android_sdk_version = conf.android_sdk_version + local android_manifest = conf.android_manifest + local android_res = conf.android_res + local android_assets = conf.android_assets + local keystore = conf.keystore + local keystore_pass = conf.keystore_pass + + assert(android_sdk_version, "android sdk version not set") + assert(android_manifest, "android manifest not set") + + local final_apk = path.join(target:targetdir(), target:basename() .. ".apk") + + -- add dependencies + local depfiles = {target:targetfile(), android_manifest, keystore} + if android_res and os.isdir(android_res) then + table.join2(depfiles, os.files(path.join(android_res, "**"))) + end + if android_assets and os.isdir(android_assets) then + table.join2(depfiles, os.files(path.join(android_assets, "**"))) + end + + depend.on_changed(function () + progress.show(opt.progress, "${color.build.target}packing.apk %s", final_apk) + + local tmp_path = path.join(target:targetdir(), "temp") + os.mkdir(tmp_path) + os.mkdir(path.join(tmp_path, "lib")) + os.mkdir(path.join(tmp_path, "lib", target:arch())) + + -- copy the target library to temp folder with name libmain.so + local libfile = path.join(tmp_path, "lib", target:arch(), "libmain.so") + os.cp(target:targetfile(), libfile) + + -- get android tool path + local android_sdkdir = target:toolchain("ndk"):config("android_sdk") + local android_build_toolver = target:toolchain("ndk"):config("build_toolver") + local sdk_tool_path = path.join(android_sdkdir, "build-tools", android_build_toolver) + + local aapt = path.join(sdk_tool_path, "aapt" .. (is_host("windows") and ".exe" or "")) + local zipalign = path.join(sdk_tool_path, "zipalign" .. (is_host("windows") and ".exe" or "")) + local apksigner = path.join(sdk_tool_path, "apksigner" .. (is_host("windows") and ".bat" or "")) + + -- pack resources + local resonly_apk = path.join(tmp_path, "res_only.apk") + local androidjar = path.join(android_sdkdir, "platforms", string.format("android-%s", android_sdk_version), + "android.jar") + assert(os.isfile(androidjar), "%s not found", androidjar) + local aapt_argv = {"package", "-f", "-M", android_manifest, "-I", androidjar, "-F", resonly_apk} + + if android_res and not os.emptydir(android_res) then + table.insert(aapt_argv, "-S") + table.insert(aapt_argv, android_res) + end + + if android_assets and not os.emptydir(android_assets) then + table.insert(aapt_argv, "-A") + table.insert(aapt_argv, android_assets) + end + + os.vrunv(aapt, aapt_argv) + + -- pack libs + os.vrunv(aapt, {"add", "res_only.apk", "lib/" .. target:arch() .."/libmain.so"}, {curdir = tmp_path}) + + -- align apk + local aligned_apk = path.join(tmp_path, "unsigned.apk") + local zipalign_argv = {"-f", "4", "res_only.apk", "unsigned.apk"} + + os.vrunv(zipalign, zipalign_argv, {curdir = tmp_path}) + + -- sign apk + local apksigner_argv = {"sign", "--ks", keystore, "--ks-pass", string.format("pass:%s", keystore_pass), "--out", + final_apk, "--in", aligned_apk} + os.vrunv(apksigner, apksigner_argv) + end, {dependfile = target:dependfile(final_apk), files = depfiles, values = {android_sdk_version, keystore_pass}}) +end diff --git a/xmake/rules/platform/android/run.lua b/xmake/rules/platform/android/run.lua new file mode 100644 index 000000000..657dad4e8 --- /dev/null +++ b/xmake/rules/platform/android/run.lua @@ -0,0 +1,56 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author keosu +-- @file run.lua +-- + +-- imports +import("core.base.tty") +import("install", {alias = "install_app"}) + +function main(target) + + -- install it first + install_app(target) + + local conf = target:extraconf("rules", "android.native_app") + local package_name = conf.package_name + local activity_name = conf.activity_name or "android.app.NativeActivity" + + local android_sdkdir = target:toolchain("ndk"):config("android_sdk") + local adb = path.join(android_sdkdir, "platform-tools", "adb") + + local run_argv = {"shell", "am", "start", "-n", package_name .. "/" .. activity_name} + + cprint("running %s ...", package_name) + os.vrunv(adb, run_argv) + + -- show logcat + local logcat_argv = {"logcat"} + if io.isatty() and (tty.has_color8() or tty.has_color256()) then + table.insert(logcat_argv, "-v") + table.insert(logcat_argv, "color") + end + local logcat_filters = conf.logcat_filters + if logcat_filters then + table.insert(logcat_argv, "-s") + for _, filter in ipairs(logcat_filters) do + table.insert(logcat_argv, filter) + end + end + os.execv(adb, logcat_argv) +end diff --git a/xmake/rules/platform/android/uninstall.lua b/xmake/rules/platform/android/uninstall.lua new file mode 100644 index 000000000..24564d631 --- /dev/null +++ b/xmake/rules/platform/android/uninstall.lua @@ -0,0 +1,32 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file uninstall.lua +-- + +function main(target) + + local conf = target:extraconf("rules", "android.native_app") + local package_name = conf.package_name + + local android_sdkdir = target:toolchain("ndk"):config("android_sdk") + local adb = path.join(android_sdkdir, "platform-tools", "adb") + + cprint("uninstalling %s ...", package_name) + os.vrunv(adb, {"uninstall", package_name}) + cprint("uninstall ok") +end diff --git a/xmake/rules/platform/android/xmake.lua b/xmake/rules/platform/android/xmake.lua new file mode 100644 index 000000000..0c58d7d09 --- /dev/null +++ b/xmake/rules/platform/android/xmake.lua @@ -0,0 +1,53 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author keosu +-- @file xmake.lua +-- + +-- define rule: build android native app with NDK +-- +-- @code +-- target("test") +-- set_kind("binary") +-- add_rules("android.native_app", { +-- android_sdk_version = "35", +-- android_manifest = "android/AndroidManifest.xml", +-- android_res = "android/res", +-- android_assets = "android/assets", +-- keystore = "android/debug.jks", +-- keystore_pass = "123456", +-- package_name = "com.raylib.demo", +-- logcat_filters = {"raydemo_android", "raylib"} +-- }) +-- @endcode +-- +rule("android.native_app") + + -- we must set_kind and add some glue files to target + on_load("load") + + -- generate android apk package + after_build("package") + + -- install android package with adb + on_install("install") + + -- uninstall android package with adb + on_uninstall("uninstall") + + -- run android app through adb + on_run("run") |
