vaderjs-native 1.0.23 → 1.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/android/build.ts +4 -2
- package/cli/binaries/fetch.ts +56 -0
- package/package.json +5 -9
- package/templates/android/.gradle/9.1.0/checksums/checksums.lock +0 -0
- package/templates/android/.gradle/9.1.0/fileChanges/last-build.bin +0 -0
- package/templates/android/.gradle/9.1.0/fileHashes/fileHashes.lock +0 -0
- package/templates/android/.gradle/9.1.0/gc.properties +0 -0
- package/templates/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/templates/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/templates/android/.gradle/vcs-1/gc.properties +0 -0
- package/templates/android/app/build.gradle.kts +0 -54
- package/templates/android/app/proguard-rules.pro +0 -21
- package/templates/android/app/src/main/AndroidManifest.xml +0 -33
- package/templates/android/app/src/main/java/myapp/AndroidBridge.kt +0 -199
- package/templates/android/app/src/main/java/myapp/MainActivity.kt +0 -133
- package/templates/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
- package/templates/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
- package/templates/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
- package/templates/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
- package/templates/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
- package/templates/android/app/src/main/res/values/strings.xml +0 -3
- package/templates/android/app/src/main/res/values/themes.xml +0 -4
- package/templates/android/build.gradle.kts +0 -5
- package/templates/android/gradle/libs.versions.toml +0 -30
- package/templates/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/templates/android/gradle/wrapper/gradle-wrapper.properties +0 -9
- package/templates/android/gradle.properties +0 -23
- package/templates/android/gradlew +0 -251
- package/templates/android/gradlew.bat +0 -94
- package/templates/android/local.properties +0 -1
- package/templates/android/settings.gradle.kts +0 -23
- package/templates/i.txt +0 -1
- package/templates/windows/App1/App1/App.xaml +0 -16
- package/templates/windows/App1/App1/App.xaml.cs +0 -50
- package/templates/windows/App1/App1/App1.csproj +0 -41
- package/templates/windows/App1/App1/App1.csproj.user +0 -12
- package/templates/windows/App1/App1/MainWindow.xaml +0 -16
- package/templates/windows/App1/App1/MainWindow.xaml.cs +0 -417
- package/templates/windows/App1/App1/Properties/PublishProfiles/win-arm64.pubxml +0 -14
- package/templates/windows/App1/App1/Properties/PublishProfiles/win-x64.pubxml +0 -14
- package/templates/windows/App1/App1/Properties/PublishProfiles/win-x86.pubxml +0 -14
- package/templates/windows/App1/App1/app.manifest +0 -17
- package/templates/windows/App1/App1/obj/App1.csproj.nuget.dgspec.json +0 -143
- package/templates/windows/App1/App1/obj/App1.csproj.nuget.g.props +0 -36
- package/templates/windows/App1/App1/obj/App1.csproj.nuget.g.targets +0 -18
- package/templates/windows/App1/App1/obj/project.assets.json +0 -3321
- package/templates/windows/App1/App1/obj/project.nuget.cache +0 -33
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs +0 -4
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App.g.cs +0 -17
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App.g.i.cs +0 -75
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App.xaml +0 -17
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App.xbf +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.AssemblyInfo.cs +0 -25
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.AssemblyInfoInputs.cache +0 -1
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.GeneratedMSBuildEditorConfig.editorconfig +0 -25
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.assets.cache +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.csproj.AssemblyReference.cache +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.csproj.BuildWithSkipAnalyzers +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.csproj.CoreCompileInputs.cache +0 -1
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.csproj.FileListAbsolute.txt +0 -99
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.csproj.Up2Date +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.designer.deps.json +0 -314
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.designer.runtimeconfig.json +0 -19
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.dll +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.genruntimeconfig.cache +0 -1
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/App1.pdb +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/MainWindow.g.cs +0 -51
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/MainWindow.g.i.cs +0 -47
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/MainWindow.xaml +0 -17
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/MainWindow.xbf +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/MultipleQualifiersPerDimensionFound.txt +0 -1
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/XamlSaveStateFile.xml +0 -1
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/XamlTypeInfo.g.cs +0 -1054
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/apphost.exe +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/embed/embed.resfiles +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/embed/embed.resfiles.intermediate +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/excluded.layout.resfiles +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/excluded.layout.resfiles.intermediate +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/filtered.layout.resfiles +0 -11
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/filtered.layout.resfiles.intermediate +0 -11
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/intermediatexaml/App1.dll +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/pri.resfiles +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/pri.resfiles.intermediate +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/priconfig.xml +0 -67
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/priconfig.xml.intermediate +0 -67
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/qualifiers.txt +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/qualifiers.txt.intermediate +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/ref/App1.dll +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/refint/App1.dll +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/resources.resfiles +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/resources.resfiles.intermediate +0 -0
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/unfiltered.layout.resfiles +0 -11
- package/templates/windows/App1/App1/obj/x64/Debug/net8.0-windows10.0.19041.0/unfiltered.layout.resfiles.intermediate +0 -11
- package/templates/windows/App1.slnx +0 -15
package/cli/android/build.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import fsSync, { existsSync } from "fs";
|
|
3
|
+
//@ts-ignore
|
|
4
|
+
import pkg from "../../package.json" assert { type: "json" };
|
|
3
5
|
import fs from "fs/promises";
|
|
4
6
|
import os from "os";
|
|
5
7
|
import { spawn, execSync } from "child_process";
|
|
@@ -7,7 +9,7 @@ import { ensureAndroidInstalled, findAndroidSdk } from "./sdk.js";
|
|
|
7
9
|
import { logger } from "../logger.js";
|
|
8
10
|
import { loadConfig } from "../../main.js";
|
|
9
11
|
import { Config } from "../../config/index.js";
|
|
10
|
-
|
|
12
|
+
import { fetchBinary } from "../binaries/fetch.js";
|
|
11
13
|
const PROJECT_ROOT = process.cwd();
|
|
12
14
|
const DIST_DIR = path.join(PROJECT_ROOT, "dist");
|
|
13
15
|
|
|
@@ -263,7 +265,7 @@ export async function addDeepLinks(buildDir: string) {
|
|
|
263
265
|
export async function buildAndroid(isDev = false) {
|
|
264
266
|
const config: Config = await loadConfig(process.cwd());
|
|
265
267
|
const APP_ID = config.app?.id || "com.vaderjs.app";
|
|
266
|
-
const BUILD_SRC =
|
|
268
|
+
const BUILD_SRC = await fetchBinary("android", pkg.version);
|
|
267
269
|
const BUILD_DIR = path.join(process.cwd(), "build", "android-src", APP_ID);
|
|
268
270
|
|
|
269
271
|
logger.step("🚀 Android Build");
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import os from "os";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import fsPromises from "fs/promises";
|
|
5
|
+
import https from "https";
|
|
6
|
+
import extract from "extract-zip";
|
|
7
|
+
import { logger } from "../logger.js";
|
|
8
|
+
|
|
9
|
+
const CACHE_ROOT = path.join(os.homedir(), ".vaderjs", "binaries");
|
|
10
|
+
|
|
11
|
+
async function download(url: string, dest: string) {
|
|
12
|
+
return new Promise<void>((resolve, reject) => {
|
|
13
|
+
https.get(url, res => {
|
|
14
|
+
if (res.statusCode !== 200) {
|
|
15
|
+
reject(new Error(`Download failed (${res.statusCode}) → ${url}`));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const file = fs.createWriteStream(dest);
|
|
20
|
+
res.pipe(file);
|
|
21
|
+
file.on("finish", () => file.close(resolve));
|
|
22
|
+
file.on("error", reject);
|
|
23
|
+
}).on("error", reject);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function fetchBinary(
|
|
28
|
+
platform: "android" | "windows" | "linux",
|
|
29
|
+
version: string
|
|
30
|
+
): Promise<string> {
|
|
31
|
+
const platformDir = path.join(CACHE_ROOT, version, platform);
|
|
32
|
+
const marker = path.join(platformDir, ".ready");
|
|
33
|
+
|
|
34
|
+
if (fs.existsSync(marker)) {
|
|
35
|
+
logger.info(`📦 Using cached ${platform} binaries (${version})`);
|
|
36
|
+
return platformDir;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
logger.info(`⬇️ Downloading ${platform} binaries v${version}`);
|
|
40
|
+
|
|
41
|
+
await fsPromises.mkdir(platformDir, { recursive: true });
|
|
42
|
+
|
|
43
|
+
const zipPath = path.join(platformDir, `${platform}.zip`);
|
|
44
|
+
const url = `https://github.com/Postr-Inc/Vaderjs-Native-Binaries/releases/download/${version}/${platform}.zip`;
|
|
45
|
+
|
|
46
|
+
await download(url, zipPath);
|
|
47
|
+
|
|
48
|
+
logger.info(`📂 Extracting ${platform}.zip`);
|
|
49
|
+
await extract(zipPath, { dir: platformDir });
|
|
50
|
+
|
|
51
|
+
await fsPromises.unlink(zipPath);
|
|
52
|
+
await fsPromises.writeFile(marker, "ok");
|
|
53
|
+
|
|
54
|
+
logger.success(`✅ ${platform} binaries ready`);
|
|
55
|
+
return platformDir;
|
|
56
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vaderjs-native",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.25",
|
|
4
4
|
"description": "Build Native Applications using Vaderjs framework.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"vaderjs": "./main.ts"
|
|
@@ -10,12 +10,8 @@
|
|
|
10
10
|
"url": "https://github.com/Postr-Inc/Vaderjs-Native"
|
|
11
11
|
},
|
|
12
12
|
"license": "MIT",
|
|
13
|
-
"dependencies": {
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
"postcss-cli": "^11.0.1",
|
|
18
|
-
"tailwindcss": "^4.1.18",
|
|
19
|
-
"vaderjs-types": "^1.0.0"
|
|
20
|
-
}
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"vaderjs-types": "latest",
|
|
15
|
+
"extract-zip":"latest"
|
|
16
|
+
}
|
|
21
17
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
File without changes
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
plugins {
|
|
2
|
-
alias(libs.plugins.android.application)
|
|
3
|
-
alias(libs.plugins.kotlin.compose)
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
android {
|
|
7
|
-
namespace = "{{APP_PACKAGE}}"
|
|
8
|
-
compileSdk {
|
|
9
|
-
version = release(36)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
defaultConfig {
|
|
13
|
-
applicationId = "{{APP_PACKAGE}}"
|
|
14
|
-
minSdk = 21
|
|
15
|
-
targetSdk = 36
|
|
16
|
-
versionCode = 1
|
|
17
|
-
versionName = "1.0"
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
buildTypes {
|
|
22
|
-
release {
|
|
23
|
-
isMinifyEnabled = false
|
|
24
|
-
proguardFiles(
|
|
25
|
-
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
26
|
-
"proguard-rules.pro"
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
compileOptions {
|
|
31
|
-
sourceCompatibility = JavaVersion.VERSION_11
|
|
32
|
-
targetCompatibility = JavaVersion.VERSION_11
|
|
33
|
-
}
|
|
34
|
-
buildFeatures {
|
|
35
|
-
compose = true
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
dependencies {
|
|
40
|
-
implementation(libs.androidx.core.ktx)
|
|
41
|
-
implementation(libs.androidx.appcompat)
|
|
42
|
-
implementation(platform(libs.androidx.compose.bom))
|
|
43
|
-
implementation(libs.androidx.compose.ui)
|
|
44
|
-
implementation(libs.androidx.compose.ui.graphics)
|
|
45
|
-
implementation(libs.androidx.compose.ui.tooling.preview)
|
|
46
|
-
implementation(libs.androidx.tv.foundation)
|
|
47
|
-
implementation(libs.androidx.tv.material)
|
|
48
|
-
implementation(libs.androidx.lifecycle.runtime.ktx)
|
|
49
|
-
implementation(libs.androidx.activity.compose)
|
|
50
|
-
androidTestImplementation(platform(libs.androidx.compose.bom))
|
|
51
|
-
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
|
|
52
|
-
debugImplementation(libs.androidx.compose.ui.tooling)
|
|
53
|
-
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
|
54
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Add project specific ProGuard rules here.
|
|
2
|
-
# You can control the set of applied configuration files using the
|
|
3
|
-
# proguardFiles setting in build.gradle.
|
|
4
|
-
#
|
|
5
|
-
# For more details, see
|
|
6
|
-
# http://developer.android.com/guide/developing/tools/proguard.html
|
|
7
|
-
|
|
8
|
-
# If your project uses WebView with JS, uncomment the following
|
|
9
|
-
# and specify the fully qualified class name to the JavaScript interface
|
|
10
|
-
# class:
|
|
11
|
-
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
|
12
|
-
# public *;
|
|
13
|
-
#}
|
|
14
|
-
|
|
15
|
-
# Uncomment this to preserve the line number information for
|
|
16
|
-
# debugging stack traces.
|
|
17
|
-
#-keepattributes SourceFile,LineNumberTable
|
|
18
|
-
|
|
19
|
-
# If you keep the line number information, uncomment this to
|
|
20
|
-
# hide the original source file name.
|
|
21
|
-
#-renamesourcefileattribute SourceFile
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
-
xmlns:tools="http://schemas.android.com/tools">
|
|
4
|
-
|
|
5
|
-
<!-- Permissions will be added by patchPermissions -->
|
|
6
|
-
|
|
7
|
-
<uses-feature
|
|
8
|
-
android:name="android.hardware.touchscreen"
|
|
9
|
-
android:required="false" />
|
|
10
|
-
<uses-feature
|
|
11
|
-
android:name="android.software.leanback"
|
|
12
|
-
android:required="false" />
|
|
13
|
-
|
|
14
|
-
<application
|
|
15
|
-
android:allowBackup="true"
|
|
16
|
-
android:banner="@mipmap/ic_launcher"
|
|
17
|
-
android:icon="@mipmap/ic_launcher"
|
|
18
|
-
android:usesCleartextTraffic="true"
|
|
19
|
-
android:label="@string/app_name"
|
|
20
|
-
android:supportsRtl="true"
|
|
21
|
-
android:theme="@style/Theme.MyApplication">
|
|
22
|
-
<activity
|
|
23
|
-
android:name=".MainActivity"
|
|
24
|
-
android:exported="true">
|
|
25
|
-
<intent-filter>
|
|
26
|
-
<action android:name="android.intent.action.MAIN" />
|
|
27
|
-
<category android:name="android.intent.category.LAUNCHER" />
|
|
28
|
-
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
|
29
|
-
</intent-filter>
|
|
30
|
-
</activity>
|
|
31
|
-
</application>
|
|
32
|
-
|
|
33
|
-
</manifest>
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import android.app.AlertDialog
|
|
2
|
-
import android.content.Context
|
|
3
|
-
import android.content.pm.PackageManager
|
|
4
|
-
import android.net.Uri
|
|
5
|
-
import android.webkit.JavascriptInterface
|
|
6
|
-
import android.webkit.WebView
|
|
7
|
-
import android.widget.Toast
|
|
8
|
-
import androidx.activity.ComponentActivity
|
|
9
|
-
import androidx.core.app.ActivityCompat
|
|
10
|
-
import androidx.core.content.ContextCompat
|
|
11
|
-
import org.json.JSONArray
|
|
12
|
-
import java.io.File
|
|
13
|
-
import java.io.FileNotFoundException
|
|
14
|
-
import java.net.HttpURLConnection
|
|
15
|
-
import java.net.URL
|
|
16
|
-
|
|
17
|
-
class AndroidBridge(
|
|
18
|
-
private val activity: ComponentActivity,
|
|
19
|
-
private val webView: WebView,
|
|
20
|
-
private val baseUrl: String
|
|
21
|
-
) {
|
|
22
|
-
|
|
23
|
-
private val PERMISSION_REQUEST_CODE = 9001
|
|
24
|
-
|
|
25
|
-
// ---- Toast ----
|
|
26
|
-
@JavascriptInterface
|
|
27
|
-
fun showToast(message: String) {
|
|
28
|
-
activity.runOnUiThread {
|
|
29
|
-
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// ---- File System Methods ----
|
|
34
|
-
@JavascriptInterface
|
|
35
|
-
fun writeFile(path: String, content: String): Boolean {
|
|
36
|
-
return try {
|
|
37
|
-
activity.openFileOutput(path, Context.MODE_PRIVATE).use {
|
|
38
|
-
it.write(content.toByteArray())
|
|
39
|
-
}
|
|
40
|
-
true
|
|
41
|
-
} catch (e: Exception) {
|
|
42
|
-
e.printStackTrace()
|
|
43
|
-
false
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
@JavascriptInterface
|
|
48
|
-
fun readFile(path: String): String {
|
|
49
|
-
return try {
|
|
50
|
-
activity.openFileInput(path).bufferedReader().use { it.readText() }
|
|
51
|
-
} catch (e: FileNotFoundException) {
|
|
52
|
-
"{\"error\":\"File not found\"}"
|
|
53
|
-
} catch (e: Exception) {
|
|
54
|
-
e.printStackTrace()
|
|
55
|
-
"{\"error\":\"${e.message}\"}"
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@JavascriptInterface
|
|
60
|
-
fun deleteFile(path: String): Boolean {
|
|
61
|
-
return try {
|
|
62
|
-
activity.deleteFile(path)
|
|
63
|
-
} catch (e: Exception) {
|
|
64
|
-
e.printStackTrace()
|
|
65
|
-
false
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
@JavascriptInterface
|
|
70
|
-
fun listFiles(): String {
|
|
71
|
-
return try {
|
|
72
|
-
val files = activity.fileList()
|
|
73
|
-
JSONArray(files.toList()).toString()
|
|
74
|
-
} catch (e: Exception) {
|
|
75
|
-
e.printStackTrace()
|
|
76
|
-
"[]"
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// ---- Permissions ----
|
|
81
|
-
@JavascriptInterface
|
|
82
|
-
fun hasPermission(name: String): Boolean {
|
|
83
|
-
val permissions = mapPermission(name)
|
|
84
|
-
return permissions.all {
|
|
85
|
-
ContextCompat.checkSelfPermission(activity, it) ==
|
|
86
|
-
PackageManager.PERMISSION_GRANTED
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
@JavascriptInterface
|
|
91
|
-
fun requestPermission(name: String) {
|
|
92
|
-
val permissions = mapPermission(name)
|
|
93
|
-
|
|
94
|
-
if (permissions.isEmpty()) {
|
|
95
|
-
sendPermissionResult(true)
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
val granted = permissions.all {
|
|
100
|
-
ContextCompat.checkSelfPermission(activity, it) ==
|
|
101
|
-
PackageManager.PERMISSION_GRANTED
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (granted) {
|
|
105
|
-
sendPermissionResult(true)
|
|
106
|
-
return
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
ActivityCompat.requestPermissions(
|
|
110
|
-
activity,
|
|
111
|
-
permissions,
|
|
112
|
-
PERMISSION_REQUEST_CODE
|
|
113
|
-
)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
fun onPermissionResult(requestCode: Int, grantResults: IntArray) {
|
|
117
|
-
if (requestCode != PERMISSION_REQUEST_CODE) return
|
|
118
|
-
val granted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
|
|
119
|
-
sendPermissionResult(granted)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
private fun sendPermissionResult(granted: Boolean) {
|
|
123
|
-
webView.post {
|
|
124
|
-
webView.evaluateJavascript(
|
|
125
|
-
"window.onNativePermissionResult && window.onNativePermissionResult($granted)",
|
|
126
|
-
null
|
|
127
|
-
)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// ---- Dialog ----
|
|
132
|
-
@JavascriptInterface
|
|
133
|
-
fun showDialog(
|
|
134
|
-
title: String,
|
|
135
|
-
message: String,
|
|
136
|
-
okText: String = "OK",
|
|
137
|
-
cancelText: String = "Cancel"
|
|
138
|
-
) {
|
|
139
|
-
activity.runOnUiThread {
|
|
140
|
-
AlertDialog.Builder(activity)
|
|
141
|
-
.setTitle(title)
|
|
142
|
-
.setMessage(message)
|
|
143
|
-
.setPositiveButton(okText) { _, _ ->
|
|
144
|
-
webView.evaluateJavascript(
|
|
145
|
-
"window.onNativeDialogResult && window.onNativeDialogResult(true)",
|
|
146
|
-
null
|
|
147
|
-
)
|
|
148
|
-
}
|
|
149
|
-
.setNegativeButton(cancelText) { _, _ ->
|
|
150
|
-
webView.evaluateJavascript(
|
|
151
|
-
"window.onNativeDialogResult && window.onNativeDialogResult(false)",
|
|
152
|
-
null
|
|
153
|
-
)
|
|
154
|
-
}
|
|
155
|
-
.setCancelable(false)
|
|
156
|
-
.show()
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// ---- Native fetch ----
|
|
161
|
-
@JavascriptInterface
|
|
162
|
-
fun nativeFetch(url: String, method: String): String {
|
|
163
|
-
return try {
|
|
164
|
-
val connection = URL(url).openConnection() as HttpURLConnection
|
|
165
|
-
connection.requestMethod = method
|
|
166
|
-
connection.connectTimeout = 5000
|
|
167
|
-
connection.readTimeout = 5000
|
|
168
|
-
val response = connection.inputStream.bufferedReader().use { it.readText() }
|
|
169
|
-
connection.disconnect()
|
|
170
|
-
response
|
|
171
|
-
} catch (e: Exception) {
|
|
172
|
-
"{\"error\":\"${e.message}\"}"
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// ---- Navigation ----
|
|
177
|
-
@JavascriptInterface
|
|
178
|
-
fun navigate(path: String?) {
|
|
179
|
-
val clean = path?.trimStart('/') ?: ""
|
|
180
|
-
webView.post {
|
|
181
|
-
val finalUrl = "$baseUrl$clean/index.html".replace("//index", "/index")
|
|
182
|
-
webView.loadUrl(finalUrl)
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// ---- Permission map ----
|
|
187
|
-
private fun mapPermission(name: String): Array<String> {
|
|
188
|
-
return when (name) {
|
|
189
|
-
"storage" -> arrayOf(
|
|
190
|
-
android.Manifest.permission.READ_EXTERNAL_STORAGE,
|
|
191
|
-
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
192
|
-
)
|
|
193
|
-
"camera" -> arrayOf(android.Manifest.permission.CAMERA)
|
|
194
|
-
"microphone" -> arrayOf(android.Manifest.permission.RECORD_AUDIO)
|
|
195
|
-
"notifications" -> arrayOf(android.Manifest.permission.POST_NOTIFICATIONS)
|
|
196
|
-
else -> emptyArray()
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
package com.mycompany.app
|
|
2
|
-
|
|
3
|
-
import android.annotation.SuppressLint
|
|
4
|
-
import android.os.Bundle
|
|
5
|
-
import android.os.Message
|
|
6
|
-
import android.view.KeyEvent
|
|
7
|
-
import android.webkit.WebChromeClient
|
|
8
|
-
import android.webkit.WebView
|
|
9
|
-
import android.webkit.WebViewClient
|
|
10
|
-
import android.widget.Toast
|
|
11
|
-
import androidx.activity.ComponentActivity
|
|
12
|
-
import androidx.activity.OnBackPressedCallback
|
|
13
|
-
|
|
14
|
-
class MainActivity : ComponentActivity() {
|
|
15
|
-
|
|
16
|
-
lateinit var webView: WebView
|
|
17
|
-
lateinit var androidBridge: AndroidBridge
|
|
18
|
-
|
|
19
|
-
private val baseUrl = "file:///android_asset/com.mycompany.app/"
|
|
20
|
-
|
|
21
|
-
@SuppressLint("SetJavaScriptEnabled", "AddJavascriptInterface")
|
|
22
|
-
override fun onCreate(savedInstanceState: Bundle?) {
|
|
23
|
-
super.onCreate(savedInstanceState)
|
|
24
|
-
|
|
25
|
-
webView = WebView(this)
|
|
26
|
-
setContentView(webView)
|
|
27
|
-
|
|
28
|
-
webView.settings.apply {
|
|
29
|
-
javaScriptEnabled = true
|
|
30
|
-
allowFileAccess = true
|
|
31
|
-
allowContentAccess = true
|
|
32
|
-
allowFileAccessFromFileURLs = true
|
|
33
|
-
allowUniversalAccessFromFileURLs = true
|
|
34
|
-
domStorageEnabled = true
|
|
35
|
-
databaseEnabled = true
|
|
36
|
-
mediaPlaybackRequiresUserGesture = false
|
|
37
|
-
|
|
38
|
-
setSupportMultipleWindows(false)
|
|
39
|
-
loadWithOverviewMode = true
|
|
40
|
-
useWideViewPort = true
|
|
41
|
-
builtInZoomControls = true
|
|
42
|
-
displayZoomControls = false
|
|
43
|
-
setSupportZoom(true)
|
|
44
|
-
|
|
45
|
-
javaScriptCanOpenWindowsAutomatically = false
|
|
46
|
-
loadsImagesAutomatically = true
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
webView.isFocusable = true
|
|
50
|
-
webView.isFocusableInTouchMode = true
|
|
51
|
-
webView.requestFocus()
|
|
52
|
-
|
|
53
|
-
androidBridge = AndroidBridge(this, webView, baseUrl)
|
|
54
|
-
webView.addJavascriptInterface(androidBridge, "Android")
|
|
55
|
-
|
|
56
|
-
webView.webViewClient = object : WebViewClient() {
|
|
57
|
-
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
|
|
58
|
-
return if (url != null && url.startsWith(baseUrl)) {
|
|
59
|
-
false
|
|
60
|
-
} else {
|
|
61
|
-
Toast.makeText(
|
|
62
|
-
this@MainActivity,
|
|
63
|
-
"Blocked external navigation",
|
|
64
|
-
Toast.LENGTH_SHORT
|
|
65
|
-
).show()
|
|
66
|
-
true
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
override fun onPageFinished(view: WebView?, url: String?) {
|
|
71
|
-
view?.evaluateJavascript(
|
|
72
|
-
"console.log('Android bridge ready:', !!window.Android)",
|
|
73
|
-
null
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
webView.webChromeClient = object : WebChromeClient() {
|
|
79
|
-
override fun onCreateWindow(
|
|
80
|
-
view: WebView?,
|
|
81
|
-
isDialog: Boolean,
|
|
82
|
-
isUserGesture: Boolean,
|
|
83
|
-
resultMsg: Message?
|
|
84
|
-
): Boolean = false
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
|
88
|
-
override fun handleOnBackPressed() {
|
|
89
|
-
webView.evaluateJavascript(
|
|
90
|
-
"window.onNativeKey && window.onNativeKey(4)",
|
|
91
|
-
null
|
|
92
|
-
)
|
|
93
|
-
}
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
webView.loadUrl(baseUrl)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
override fun onRequestPermissionsResult(
|
|
100
|
-
requestCode: Int,
|
|
101
|
-
permissions: Array<out String>,
|
|
102
|
-
grantResults: IntArray
|
|
103
|
-
) {
|
|
104
|
-
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
105
|
-
androidBridge.onPermissionResult(requestCode, grantResults)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
@SuppressLint("RestrictedApi")
|
|
109
|
-
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
|
110
|
-
if (event.action == KeyEvent.ACTION_DOWN) {
|
|
111
|
-
val handled = when (event.keyCode) {
|
|
112
|
-
KeyEvent.KEYCODE_DPAD_UP,
|
|
113
|
-
KeyEvent.KEYCODE_DPAD_DOWN,
|
|
114
|
-
KeyEvent.KEYCODE_DPAD_LEFT,
|
|
115
|
-
KeyEvent.KEYCODE_DPAD_RIGHT,
|
|
116
|
-
KeyEvent.KEYCODE_DPAD_CENTER,
|
|
117
|
-
KeyEvent.KEYCODE_BACK,
|
|
118
|
-
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
|
|
119
|
-
webView.post {
|
|
120
|
-
webView.evaluateJavascript(
|
|
121
|
-
"window.onNativeKey && window.onNativeKey(${event.keyCode})",
|
|
122
|
-
null
|
|
123
|
-
)
|
|
124
|
-
}
|
|
125
|
-
true
|
|
126
|
-
}
|
|
127
|
-
else -> false
|
|
128
|
-
}
|
|
129
|
-
if (handled) return true
|
|
130
|
-
}
|
|
131
|
-
return super.dispatchKeyEvent(event)
|
|
132
|
-
}
|
|
133
|
-
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
[versions]
|
|
2
|
-
agp = "9.0.0"
|
|
3
|
-
coreKtx = "1.10.1"
|
|
4
|
-
appcompat = "1.6.1"
|
|
5
|
-
kotlin = "2.0.21"
|
|
6
|
-
composeBom = "2024.09.00"
|
|
7
|
-
tvFoundation = "1.0.0-alpha07"
|
|
8
|
-
tvMaterial = "1.0.0-alpha07"
|
|
9
|
-
lifecycleRuntimeKtx = "2.6.1"
|
|
10
|
-
activityCompose = "1.8.0"
|
|
11
|
-
|
|
12
|
-
[libraries]
|
|
13
|
-
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
|
14
|
-
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
|
15
|
-
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
|
|
16
|
-
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
|
|
17
|
-
androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
|
|
18
|
-
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
|
|
19
|
-
androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
|
|
20
|
-
androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
|
21
|
-
androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
|
22
|
-
androidx-tv-foundation = { group = "androidx.tv", name = "tv-foundation", version.ref = "tvFoundation" }
|
|
23
|
-
androidx-tv-material = { group = "androidx.tv", name = "tv-material", version.ref = "tvMaterial" }
|
|
24
|
-
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
|
|
25
|
-
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
|
|
26
|
-
|
|
27
|
-
[plugins]
|
|
28
|
-
android-application = { id = "com.android.application", version.ref = "agp" }
|
|
29
|
-
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
|
30
|
-
|
|
Binary file
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
#Tue Jan 20 13:18:12 PST 2026
|
|
2
|
-
distributionBase=GRADLE_USER_HOME
|
|
3
|
-
distributionPath=wrapper/dists
|
|
4
|
-
distributionSha256Sum=a17ddd85a26b6a7f5ddb71ff8b05fc5104c0202c6e64782429790c933686c806
|
|
5
|
-
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
|
|
6
|
-
networkTimeout=10000
|
|
7
|
-
validateDistributionUrl=true
|
|
8
|
-
zipStoreBase=GRADLE_USER_HOME
|
|
9
|
-
zipStorePath=wrapper/dists
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Project-wide Gradle settings.
|
|
2
|
-
# IDE (e.g. Android Studio) users:
|
|
3
|
-
# Gradle settings configured through the IDE *will override*
|
|
4
|
-
# any settings specified in this file.
|
|
5
|
-
# For more details on how to configure your build environment visit
|
|
6
|
-
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
|
7
|
-
# Specifies the JVM arguments used for the daemon process.
|
|
8
|
-
# The setting is particularly useful for tweaking memory settings.
|
|
9
|
-
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
|
10
|
-
# When configured, Gradle will run in incubating parallel mode.
|
|
11
|
-
# This option should only be used with decoupled projects. For more details, visit
|
|
12
|
-
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
|
|
13
|
-
# org.gradle.parallel=true
|
|
14
|
-
# AndroidX package structure to make it clearer which packages are bundled with the
|
|
15
|
-
# Android operating system, and which are packaged with your app's APK
|
|
16
|
-
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
|
17
|
-
android.useAndroidX=true
|
|
18
|
-
# Kotlin code style for this project: "official" or "obsolete":
|
|
19
|
-
kotlin.code.style=official
|
|
20
|
-
# Enables namespacing of each library's R class so that its R class includes only the
|
|
21
|
-
# resources declared in the library itself and none from the library's dependencies,
|
|
22
|
-
# thereby reducing the size of the R class for that library
|
|
23
|
-
android.nonTransitiveRClass=true
|