diff --git a/.github/workflows/build-apk.yml b/.github/workflows/build-apk.yml
new file mode 100644
index 0000000..b1fe5eb
--- /dev/null
+++ b/.github/workflows/build-apk.yml
@@ -0,0 +1,31 @@
+name: Build APK
+
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ assemble-debug-apk:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out repository
+ uses: actions/checkout@v4
+
+ - name: Set up JDK
+ uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: '17'
+
+ - name: Set up Gradle
+ uses: gradle/actions/setup-gradle@v4
+
+ - name: Build debug APK
+ run: gradle assembleDebug
+
+ - name: Upload APK artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: iwd-debug-apk
+ path: app/build/outputs/apk/debug/app-debug.apk
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1773035
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+.gradle/
+build/
+app/build/
+local.properties
+*.apk
+*.aab
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c98f9a2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+# IWD Web APK
+
+A minimal Android WebView application that embeds `https://iwd.illusd.com/` as an installable APK.
+
+## Download the APK
+
+Every push and pull request runs the **Build APK** GitHub Actions workflow. Open the workflow run and download the `iwd-debug-apk` artifact; it contains `app-debug.apk`.
+
+## Build locally
+
+```bash
+gradle assembleDebug
+```
+
+The debug APK is generated at `app/build/outputs/apk/debug/app-debug.apk`.
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..f11d67a
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,14 @@
+plugins { id 'com.android.application' }
+
+android {
+ namespace 'com.illusd.iwdwebapk'
+ compileSdk 35
+
+ defaultConfig {
+ applicationId 'com.illusd.iwdwebapk'
+ minSdk 23
+ targetSdk 35
+ versionCode 1
+ versionName '1.0'
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..2318666
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/illusd/iwdwebapk/MainActivity.java b/app/src/main/java/com/illusd/iwdwebapk/MainActivity.java
new file mode 100644
index 0000000..a6a326e
--- /dev/null
+++ b/app/src/main/java/com/illusd/iwdwebapk/MainActivity.java
@@ -0,0 +1,100 @@
+package com.illusd.iwdwebapk;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.net.http.SslError;
+import android.os.Bundle;
+import android.view.View;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.ProgressBar;
+import android.widget.FrameLayout;
+
+public class MainActivity extends Activity {
+ private WebView webView;
+
+ @SuppressLint("SetJavaScriptEnabled")
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FrameLayout root = new FrameLayout(this);
+ webView = new WebView(this);
+ ProgressBar progressBar = new ProgressBar(this);
+ FrameLayout.LayoutParams progressParams = new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT
+ );
+ progressParams.gravity = android.view.Gravity.CENTER;
+
+ root.addView(webView, new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT
+ ));
+ root.addView(progressBar, progressParams);
+ setContentView(root);
+
+ WebSettings settings = webView.getSettings();
+ settings.setJavaScriptEnabled(true);
+ settings.setDomStorageEnabled(true);
+ settings.setLoadWithOverviewMode(true);
+ settings.setUseWideViewPort(true);
+ settings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
+
+ webView.setWebViewClient(new WebViewClient() {
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+ view.loadUrl(request.getUrl().toString());
+ return true;
+ }
+
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ progressBar.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ progressBar.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+ handler.cancel();
+ }
+ });
+
+ if (savedInstanceState == null) {
+ webView.loadUrl(getString(R.string.target_url));
+ } else {
+ webView.restoreState(savedInstanceState);
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ webView.saveState(outState);
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (webView.canGoBack()) {
+ webView.goBack();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (webView != null) {
+ webView.destroy();
+ }
+ super.onDestroy();
+ }
+}
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..8dd50cb
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,3 @@
+
+ #FFFFFF
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..0aaeefc
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+ IWD
+ https://iwd.illusd.com/
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..77ef389
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..5b7ccba
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,3 @@
+plugins {
+ id 'com.android.application' version '8.7.3' apply false
+}
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..c3242eb
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,10 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS); repositories { google(); mavenCentral() } }
+rootProject.name = 'IWDWebApk'
+include ':app'