├── .gitignore
├── .gitmodules
├── .vscode
├── launch.json
└── settings.json
├── LICENSE
├── README.md
├── Usages.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── JsEngineSonicBridge.js
│ ├── sonic.js
│ ├── sonic.kbc1
│ ├── test.js
│ └── test.kbc1
│ ├── java
│ └── com
│ │ └── shiqi
│ │ └── testquickjs
│ │ ├── HippyJsEngine.kt
│ │ ├── MainActivity.kt
│ │ ├── QuickJsEngine.kt
│ │ └── ui
│ │ └── theme
│ │ ├── Color.kt
│ │ ├── Theme.kt
│ │ └── Type.kt
│ └── res
│ ├── drawable
│ ├── ic_launcher_background.xml
│ └── ic_launcher_foreground.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-mdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── themes.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── quickjs-android
├── .gitignore
├── CMakeLists.txt
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── c
│ ├── java-helper.c
│ ├── java-helper.h
│ ├── java-method.c
│ ├── java-method.h
│ ├── java-object.c
│ ├── java-object.h
│ └── quickjs-jni.c
│ └── java
│ └── com
│ └── shiqi
│ └── quickjs
│ ├── ArrayTypeAdapter.java
│ ├── InterfaceTypeAdapter.java
│ ├── JNIHelper.java
│ ├── JSArray.java
│ ├── JSArrayBuffer.java
│ ├── JSBoolean.java
│ ├── JSContext.java
│ ├── JSDataException.java
│ ├── JSEvaluationException.java
│ ├── JSException.java
│ ├── JSFloat64.java
│ ├── JSFunction.java
│ ├── JSFunctionCallback.java
│ ├── JSInt.java
│ ├── JSInternal.java
│ ├── JSNull.java
│ ├── JSNumber.java
│ ├── JSObject.java
│ ├── JSRuntime.java
│ ├── JSString.java
│ ├── JSSymbol.java
│ ├── JSUndefined.java
│ ├── JSValue.java
│ ├── JSValueAdapter.java
│ ├── JavaMethod.java
│ ├── JavaType.java
│ ├── JavaTypes.java
│ ├── NativeCleaner.java
│ ├── PromiseExecutor.java
│ ├── QuickJS.java
│ ├── StandardTypeAdapters.java
│ └── TypeAdapter.java
├── quickjs
├── .gitattributes
├── .gitignore
├── CMakeLists.txt
├── Changelog
├── README.md
├── TODO
├── VERSION
├── doc
│ ├── jsbignum.texi
│ └── quickjs.texi
├── examples
│ ├── fib.c
│ ├── fib_module.js
│ ├── hello.js
│ ├── hello_module.js
│ ├── pi_bigdecimal.js
│ ├── pi_bigfloat.js
│ ├── pi_bigint.js
│ ├── point.c
│ ├── test_fib.js
│ └── test_point.js
├── include
│ └── quickjs
│ │ ├── cutils.h
│ │ ├── libbf.h
│ │ ├── libregexp-opcode.h
│ │ ├── libregexp.h
│ │ ├── libunicode-table.h
│ │ ├── libunicode.h
│ │ ├── list.h
│ │ ├── quickjs-atom.h
│ │ ├── quickjs-opcode.h
│ │ └── quickjs.h
├── qjs.c
├── qjsc.c
├── qjscalc.c
├── qjscalc.js
├── quickjs-libc.c
├── quickjs-libc.h
├── release.sh
├── repl.c
├── repl.js
├── run-test262.c
├── scripts
│ ├── build.sh
│ ├── ci.sh
│ └── test.sh
├── src
│ ├── CMakeLists.txt
│ ├── core
│ │ ├── base.h
│ │ ├── builtins
│ │ │ ├── js-array.c
│ │ │ ├── js-array.h
│ │ │ ├── js-async-function.c
│ │ │ ├── js-async-function.h
│ │ │ ├── js-async-generator.c
│ │ │ ├── js-async-generator.h
│ │ │ ├── js-atomics.c
│ │ │ ├── js-atomics.h
│ │ │ ├── js-big-num.c
│ │ │ ├── js-big-num.h
│ │ │ ├── js-boolean.c
│ │ │ ├── js-boolean.h
│ │ │ ├── js-closures.c
│ │ │ ├── js-closures.h
│ │ │ ├── js-date.c
│ │ │ ├── js-date.h
│ │ │ ├── js-function.c
│ │ │ ├── js-function.h
│ │ │ ├── js-generator.c
│ │ │ ├── js-generator.h
│ │ │ ├── js-json.c
│ │ │ ├── js-json.h
│ │ │ ├── js-map.c
│ │ │ ├── js-map.h
│ │ │ ├── js-math.c
│ │ │ ├── js-math.h
│ │ │ ├── js-number.c
│ │ │ ├── js-number.h
│ │ │ ├── js-object.c
│ │ │ ├── js-object.h
│ │ │ ├── js-operator.c
│ │ │ ├── js-operator.h
│ │ │ ├── js-promise.c
│ │ │ ├── js-promise.h
│ │ │ ├── js-proxy.c
│ │ │ ├── js-proxy.h
│ │ │ ├── js-reflect.c
│ │ │ ├── js-reflect.h
│ │ │ ├── js-regexp.c
│ │ │ ├── js-regexp.h
│ │ │ ├── js-string.c
│ │ │ ├── js-string.h
│ │ │ ├── js-symbol.c
│ │ │ ├── js-symbol.h
│ │ │ ├── js-typed-array.c
│ │ │ └── js-typed-array.h
│ │ ├── bytecode.c
│ │ ├── bytecode.h
│ │ ├── convertion.c
│ │ ├── convertion.h
│ │ ├── exception.c
│ │ ├── exception.h
│ │ ├── function.c
│ │ ├── function.h
│ │ ├── gc.c
│ │ ├── gc.h
│ │ ├── ic.c
│ │ ├── ic.h
│ │ ├── malloc.c
│ │ ├── malloc.h
│ │ ├── memory.c
│ │ ├── memory.h
│ │ ├── misc
│ │ │ ├── debug.c
│ │ │ └── debug.h
│ │ ├── module.c
│ │ ├── module.h
│ │ ├── object.c
│ │ ├── object.h
│ │ ├── parser.c
│ │ ├── parser.h
│ │ ├── runtime.c
│ │ ├── runtime.h
│ │ ├── shape.c
│ │ ├── shape.h
│ │ ├── string.c
│ │ ├── string.h
│ │ └── types.h
│ ├── cutils.c
│ ├── libbf.c
│ ├── libregexp.c
│ └── libunicode.c
├── test262.conf
├── test262o.conf
├── tests
│ ├── bjson.c
│ ├── microbench.js
│ ├── test262.patch
│ ├── test_bignum.js
│ ├── test_bjson.js
│ ├── test_builtin.js
│ ├── test_closure.js
│ ├── test_ic_atom_free.js
│ ├── test_language.js
│ ├── test_line_column_num.js
│ ├── test_loop.js
│ ├── test_op_overloading.js
│ ├── test_promise_gc_crash.js
│ ├── test_qjscalc.js
│ ├── test_std.js
│ ├── test_worker.js
│ └── test_worker_module.js
├── unicode_download.sh
├── unicode_gen.c
└── unicode_gen_def.h
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 | /.idea/
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "mimalloc"]
2 | path = quickjs/vendor/mimalloc
3 | url = https://github.com/microsoft/mimalloc.git
4 | branch = v2.1.2
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "lldb",
9 | "request": "launch",
10 | "name": "Debug",
11 | "program": "${workspaceFolder}/quickjs/bin/qjs",
12 | "args": [],
13 | "cwd": "${workspaceFolder}"
14 | }
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cmake.sourceDirectory": "${workspaceFolder}/quickjs",
3 | "cmake.cmakePath": "/usr/local/bin/cmake",
4 | "files.associations": {
5 | "js-array.h": "c"
6 | }
7 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | QuickJS Javascript Engine
2 |
3 | Copyright (c) 2017-2021 Fabrice Bellard
4 | Copyright (c) 2017-2021 Charlie Gordon
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # QuickJS Android
2 |
3 | > Self-maintained QuickJS Android Bindings.
4 |
5 | ## Usage
6 |
7 | 1. Download the latest `.aar` archive from [release](https://github.com/shiqimei/quickjs-android/releases) page;
8 | 2. In Android Studio: `File > New > New Module > Import .JAR/.AAR Package`, locate `.aar`, click `Finish`.
9 |
10 | ```Java
11 | QuickJS quickJS = new QuickJS.Builder().build();
12 | try (JSRuntime runtime = quickJS.createJSRuntime()) {
13 | try (JSContext context = runtime.createJSContext()) {
14 | String script1 = "" +
15 | "function fibonacci(n) {" +
16 | " if (n == 0 || n == 1) return n;" +
17 | " return fibonacci(n - 1) + fibonacci(n - 2);" +
18 | "}";
19 | // Evaluate a script without return value
20 | context.evaluate(script1, "fibonacci.js");
21 |
22 | String script2 = "fibonacci(10);";
23 | // Evaluate a script with return value
24 | int result = context.evaluate(script2, "fibonacci.js", int.class);
25 | assertEquals(55, result);
26 | }
27 | }
28 | ```
29 |
30 | See [Usages.md](./Usages.md) for advanced usages.
31 |
32 | ## Develop
33 |
34 | ```bash
35 | git clone --recurse-submodules https://github.com/shiqimei/quickjs-android.git
36 | ```
37 |
38 | Open the folder `quickjs-android` in Android Studio.
39 |
40 | ## Benchmark
41 |
42 | This is a non-serious benchmark. The purpose is to compare the performance of QuickJS and V8 on Android.
43 |
44 | | Engine | v8 | QuickJS (Script Mode) | QuickJS (Bytecode Mode) |
45 | | :----: | :--: | :-------------------: | :---------------------: |
46 | | init | 30ms | 18ms | 18ms |
47 | | eval | 29ms | 282ms | 48ms |
48 | | total | 59ms | 300ms | 56ms |
49 |
50 | - Device: Huawei P30 Pro (Kirin 980), Android 10.
51 | - Test JavaScript File: `asset:/sonic.js` (189 KB).
52 |
53 | ### Conclusion
54 |
55 | 1. Even when operating in bytecode mode, QuickJS's evaluation time is notably higher than V8's, and this disparity intensifies as the JavaScript file size increases.
56 | 2. QuickJS's initialization time is slightly lower than V8's, and this advantage is constant despite of file sizes.
57 |
58 | ## Acknowledgement
59 |
60 | 1. [bellard/quickjs](https://github.com/bellard/quickjs) QuickJS official repository.
61 | 2. [seven332/quickjs-android](https://github.com/seven332/quickjs-android) QuickJS Android Wrapper.
62 | 3. [openwebf/quickjs](https://github.com/openwebf/quickjs) Optimized quickjs mantained by OpenWebF team.
63 | 4. [taoweiji/quickjs-android](https://github.com/taoweiji/quickjs-android) Android Bindings for QuickJS, A fine little javascript engine.
64 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | namespace 'com.shiqi.testquickjs'
8 | compileSdk 33
9 |
10 | defaultConfig {
11 | applicationId "com.shiqi.testquickjs"
12 | minSdk 24
13 | targetSdk 33
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | vectorDrawables {
19 | useSupportLibrary true
20 | }
21 | }
22 |
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | compileOptions {
30 | sourceCompatibility JavaVersion.VERSION_1_8
31 | targetCompatibility JavaVersion.VERSION_1_8
32 | }
33 | kotlinOptions {
34 | jvmTarget = '1.8'
35 | }
36 | buildFeatures {
37 | compose true
38 | }
39 | composeOptions {
40 | kotlinCompilerExtensionVersion '1.4.5'
41 | }
42 | packagingOptions {
43 | resources {
44 | excludes += '/META-INF/{AL2.0,LGPL2.1}'
45 | }
46 | }
47 | }
48 |
49 | dependencies {
50 |
51 | implementation project(':quickjs-android')
52 | implementation("com.tencent.hippy:hippy-common:2.12.1")
53 |
54 | implementation 'androidx.core:core-ktx:1.9.0'
55 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
56 | implementation 'androidx.activity:activity-compose:1.5.1'
57 | implementation platform('androidx.compose:compose-bom:2022.10.00')
58 | implementation 'androidx.compose.ui:ui'
59 | implementation 'androidx.compose.ui:ui-graphics'
60 | implementation 'androidx.compose.ui:ui-tooling-preview'
61 | implementation 'androidx.compose.material3:material3'
62 | testImplementation 'junit:junit:4.13.2'
63 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
64 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
65 | androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00')
66 | androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
67 | debugImplementation 'androidx.compose.ui:ui-tooling'
68 | debugImplementation 'androidx.compose.ui:ui-test-manifest'
69 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
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
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/assets/JsEngineSonicBridge.js:
--------------------------------------------------------------------------------
1 | var sonicNativeBridgeCore=function(){"use strict";function c(e,r){for(var t=0;t Unit
46 | ) {
47 | val colorScheme = when {
48 | dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
49 | val context = LocalContext.current
50 | if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
51 | }
52 |
53 | darkTheme -> DarkColorScheme
54 | else -> LightColorScheme
55 | }
56 | val view = LocalView.current
57 | if (!view.isInEditMode) {
58 | SideEffect {
59 | val window = (view.context as Activity).window
60 | window.statusBarColor = colorScheme.primary.toArgb()
61 | WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
62 | }
63 | }
64 |
65 | MaterialTheme(
66 | colorScheme = colorScheme,
67 | typography = Typography,
68 | content = content
69 | )
70 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/shiqi/testquickjs/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package com.shiqi.testquickjs.ui.theme
2 |
3 | import androidx.compose.material3.Typography
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.FontFamily
6 | import androidx.compose.ui.text.font.FontWeight
7 | import androidx.compose.ui.unit.sp
8 |
9 | // Set of Material typography styles to start with
10 | val Typography = Typography(
11 | bodyLarge = TextStyle(
12 | fontFamily = FontFamily.Default,
13 | fontWeight = FontWeight.Normal,
14 | fontSize = 16.sp,
15 | lineHeight = 24.sp,
16 | letterSpacing = 0.5.sp
17 | )
18 | /* Other default text styles to override
19 | titleLarge = TextStyle(
20 | fontFamily = FontFamily.Default,
21 | fontWeight = FontWeight.Normal,
22 | fontSize = 22.sp,
23 | lineHeight = 28.sp,
24 | letterSpacing = 0.sp
25 | ),
26 | labelSmall = TextStyle(
27 | fontFamily = FontFamily.Default,
28 | fontWeight = FontWeight.Medium,
29 | fontSize = 11.sp,
30 | lineHeight = 16.sp,
31 | letterSpacing = 0.5.sp
32 | )
33 | */
34 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenQuickJS/quickjs-android/0319d76cd984fe6d591760e7e30a3bb003a0d768/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenQuickJS/quickjs-android/0319d76cd984fe6d591760e7e30a3bb003a0d768/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenQuickJS/quickjs-android/0319d76cd984fe6d591760e7e30a3bb003a0d768/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenQuickJS/quickjs-android/0319d76cd984fe6d591760e7e30a3bb003a0d768/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenQuickJS/quickjs-android/0319d76cd984fe6d591760e7e30a3bb003a0d768/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenQuickJS/quickjs-android/0319d76cd984fe6d591760e7e30a3bb003a0d768/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenQuickJS/quickjs-android/0319d76cd984fe6d591760e7e30a3bb003a0d768/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenQuickJS/quickjs-android/0319d76cd984fe6d591760e7e30a3bb003a0d768/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenQuickJS/quickjs-android/0319d76cd984fe6d591760e7e30a3bb003a0d768/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenQuickJS/quickjs-android/0319d76cd984fe6d591760e7e30a3bb003a0d768/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | app
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | id 'com.android.application' version '8.1.0-alpha07' apply false
4 | id 'com.android.library' version '8.1.0-alpha07' apply false
5 | id 'org.jetbrains.kotlin.android' version '1.8.20' apply false
6 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
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. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec: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
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenQuickJS/quickjs-android/0319d76cd984fe6d591760e7e30a3bb003a0d768/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jun 07 16:35:15 CST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/quickjs-android/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/quickjs-android/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.4.1)
2 |
3 | project(quickjs-android)
4 |
5 | if (CMAKE_BUILD_TYPE STREQUAL "Debug")
6 | option(LEAK_TRIGGER "Add a leak trigger" ON)
7 | else ()
8 | option(LEAK_TRIGGER "Add a leak trigger" OFF)
9 | endif (CMAKE_BUILD_TYPE STREQUAL "Debug")
10 |
11 | include_directories(../quickjs/include)
12 | add_subdirectory(../quickjs ${CMAKE_CURRENT_BINARY_DIR}/quickjs)
13 |
14 | set(QUICKJS_ANDROID_SOURCES
15 | src/main/c/quickjs-jni.c
16 | src/main/c/java-method.c
17 | src/main/c/java-object.c
18 | src/main/c/java-helper.c
19 | )
20 |
21 | if (LEAK_TRIGGER)
22 | set(COMMON_FLAGS -DLEAK_TRIGGER)
23 | else ()
24 | set(COMMON_FLAGS)
25 | endif (LEAK_TRIGGER)
26 |
27 | add_library(quickjs-android SHARED ${QUICKJS_ANDROID_SOURCES})
28 | find_library(log-lib log)
29 | target_compile_options(quickjs-android PRIVATE ${COMMON_FLAGS})
30 | target_link_libraries(quickjs-android PRIVATE quickjs mimalloc ${log-lib})
31 |
--------------------------------------------------------------------------------
/quickjs-android/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | namespace 'com.shiqi.quickjs'
8 | compileSdk 33
9 |
10 | defaultConfig {
11 | minSdk 22
12 | targetSdk 33
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | vectorDrawables {
18 | useSupportLibrary true
19 | }
20 |
21 | // build quickjs
22 | externalNativeBuild {
23 | cmake {
24 | targets 'quickjs-android'
25 | arguments '-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON'
26 | }
27 | }
28 | ndk {
29 | //noinspection ChromeOsAbiSupport
30 | abiFilters 'armeabi-v7a', 'arm64-v8a'
31 | }
32 | }
33 |
34 | externalNativeBuild {
35 | cmake {
36 | path 'CMakeLists.txt'
37 | }
38 | }
39 |
40 | buildTypes {
41 | release {
42 | minifyEnabled false
43 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
44 | }
45 | }
46 | compileOptions {
47 | sourceCompatibility JavaVersion.VERSION_1_8
48 | targetCompatibility JavaVersion.VERSION_1_8
49 | }
50 | kotlinOptions {
51 | jvmTarget = '1.8'
52 | }
53 | buildFeatures {
54 | compose true
55 | }
56 | composeOptions {
57 | kotlinCompilerExtensionVersion '1.4.5'
58 | }
59 | packagingOptions {
60 | resources {
61 | excludes += '/META-INF/{AL2.0,LGPL2.1}'
62 | }
63 | }
64 | }
65 |
66 | dependencies {
67 | implementation 'androidx.annotation:annotation:1.6.0'
68 | }
--------------------------------------------------------------------------------
/quickjs-android/proguard-rules.pro:
--------------------------------------------------------------------------------
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
--------------------------------------------------------------------------------
/quickjs-android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/quickjs-android/src/main/c/java-helper.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "java-helper.h"
4 |
5 | #define MAX_MSG_SIZE 1024
6 |
7 | jint throw_exception(JNIEnv *env, const char *exception_name, const char *message, ...) {
8 | char formatted_message[MAX_MSG_SIZE];
9 | va_list va_args;
10 | va_start(va_args, message);
11 | vsnprintf(formatted_message, MAX_MSG_SIZE, message, va_args);
12 | va_end(va_args);
13 |
14 | jclass exception_class = (*env)->FindClass(env, exception_name);
15 | if (exception_class == NULL) {
16 | return -1;
17 | }
18 |
19 | return (*env)->ThrowNew(env, exception_class, formatted_message);
20 | }
21 |
--------------------------------------------------------------------------------
/quickjs-android/src/main/c/java-helper.h:
--------------------------------------------------------------------------------
1 | #ifndef QUICKJS_ANDROID_JAVA_HELPER_H
2 | #define QUICKJS_ANDROID_JAVA_HELPER_H
3 |
4 | #include
5 |
6 | #define CLASS_NAME_ILLEGAL_STATE_EXCEPTION "java/lang/IllegalStateException"
7 | #define CLASS_NAME_JS_DATA_EXCEPTION "com/shiqi/quickjs/JSDataException"
8 |
9 | #define THROW_EXCEPTION(ENV, EXCEPTION_NAME, ...) \
10 | do { \
11 | throw_exception((ENV), (EXCEPTION_NAME), __VA_ARGS__); \
12 | return; \
13 | } while (0)
14 |
15 | #define THROW_EXCEPTION_RET(ENV, EXCEPTION_NAME, ...) \
16 | do { \
17 | throw_exception((ENV), (EXCEPTION_NAME), __VA_ARGS__); \
18 | return 0; \
19 | } while (0)
20 |
21 | #define THROW_ILLEGAL_STATE_EXCEPTION(ENV, ...) \
22 | THROW_EXCEPTION(ENV, CLASS_NAME_ILLEGAL_STATE_EXCEPTION, __VA_ARGS__)
23 |
24 | #define THROW_ILLEGAL_STATE_EXCEPTION_RET(ENV, ...) \
25 | THROW_EXCEPTION_RET(ENV, CLASS_NAME_ILLEGAL_STATE_EXCEPTION, __VA_ARGS__)
26 |
27 | #define THROW_JS_DATA_EXCEPTION(ENV, ...) \
28 | THROW_EXCEPTION(ENV, CLASS_NAME_JS_DATA_EXCEPTION, __VA_ARGS__)
29 |
30 | #define THROW_JS_DATA_EXCEPTION_RET(ENV, ...) \
31 | THROW_EXCEPTION_RET(ENV, CLASS_NAME_JS_DATA_EXCEPTION, __VA_ARGS__)
32 |
33 | #define CHECK_NULL(ENV, POINTER, MESSAGE) \
34 | do { \
35 | if ((POINTER) == NULL) { \
36 | THROW_ILLEGAL_STATE_EXCEPTION((ENV), (MESSAGE)); \
37 | } \
38 | } while (0)
39 |
40 | #define CHECK_NULL_RET(ENV, POINTER, MESSAGE) \
41 | do { \
42 | if ((POINTER) == NULL) { \
43 | THROW_ILLEGAL_STATE_EXCEPTION_RET((ENV), (MESSAGE)); \
44 | } \
45 | } while (0)
46 |
47 | #define CHECK_FALSE_RET(ENV, STATEMENT, MESSAGE) \
48 | do { \
49 | if (!(STATEMENT)) { \
50 | THROW_ILLEGAL_STATE_EXCEPTION_RET((ENV), (MESSAGE)); \
51 | } \
52 | } while (0)
53 |
54 | jint throw_exception(JNIEnv *env, const char *exception_name, const char *message, ...);
55 |
56 | #define OBTAIN_ENV(VM) \
57 | JNIEnv *env = NULL; \
58 | int __require_detach__ = 0; \
59 | do { \
60 | (*(VM))->GetEnv((VM), (void **) &env, JNI_VERSION_1_6); \
61 | if (env == NULL) __require_detach__ = (*(VM))->AttachCurrentThread((VM), &env, NULL) == JNI_OK; \
62 | } while (0)
63 |
64 | #define RELEASE_ENV(VM) \
65 | do { \
66 | if (__require_detach__) (*(VM))->DetachCurrentThread((VM)); \
67 | } while (0)
68 |
69 | #endif //QUICKJS_ANDROID_JAVA_HELPER_H
70 |
--------------------------------------------------------------------------------
/quickjs-android/src/main/c/java-method.h:
--------------------------------------------------------------------------------
1 | #ifndef QUICKJS_ANDROID_JAVA_METHOD_H
2 | #define QUICKJS_ANDROID_JAVA_METHOD_H
3 |
4 | #include
5 | #include
6 |
7 | int java_method_init(JNIEnv *env);
8 |
9 | int java_method_init_context(JSContext *ctx);
10 |
11 | JSValue QJ_NewJavaMethod(JSContext *ctx, JNIEnv *env, jobject js_context, jboolean is_static, jobject callee, jmethodID method, jobject return_type, int arg_count, jobject *arg_types, jboolean is_callback_method);
12 |
13 | #endif //QUICKJS_ANDROID_JAVA_METHOD_H
14 |
--------------------------------------------------------------------------------
/quickjs-android/src/main/c/java-object.c:
--------------------------------------------------------------------------------
1 | #include "java-object.h"
2 | #include "java-helper.h"
3 |
4 | static JSClassID java_object_class_id;
5 |
6 | typedef struct {
7 | JavaVM *vm;
8 | jobject object;
9 | } JavaObjectData;
10 |
11 | static void java_object_finalizer(JSRuntime *rt, JSValue val) {
12 | JavaObjectData *data = JS_GetOpaque(val, java_object_class_id);
13 |
14 | OBTAIN_ENV(data->vm);
15 |
16 | if (env != NULL) {
17 | (*env)->DeleteGlobalRef(env, data->object);
18 | }
19 |
20 | RELEASE_ENV(data->vm);
21 |
22 | js_free_rt(rt, data);
23 | }
24 |
25 | static JSClassDef java_object_class = {
26 | "JavaObject",
27 | .finalizer = java_object_finalizer
28 | };
29 |
30 | int java_object_init_context(JSContext *ctx) {
31 | JS_NewClassID(&java_object_class_id);
32 | if (JS_NewClass(JS_GetRuntime(ctx), java_object_class_id, &java_object_class)) return -1;
33 | return 0;
34 | }
35 |
36 | JSValue QJ_NewJavaObject(JSContext *ctx, JNIEnv *env, jobject object) {
37 | JSRuntime *rt = JS_GetRuntime(ctx);
38 |
39 | JavaObjectData *data = js_malloc_rt(rt, sizeof(JavaObjectData));
40 | if (data == NULL) return JS_ThrowOutOfMemory(ctx);
41 |
42 | JSValue value = JS_NewObjectClass(ctx, java_object_class_id);
43 | if (JS_IsException(value)) {
44 | js_free_rt(rt, data);
45 | return value;
46 | }
47 |
48 | (*env)->GetJavaVM(env, &data->vm);
49 | data->object = (*env)->NewGlobalRef(env, object);
50 |
51 | JS_SetOpaque(value, data);
52 |
53 | return value;
54 | }
55 |
56 | jobject QJ_GetJavaObject(JSContext __unused *ctx, JSValueConst val) {
57 | JavaObjectData *data = JS_GetOpaque(val, java_object_class_id);
58 | return data != NULL ? data->object : NULL;
59 | }
60 |
--------------------------------------------------------------------------------
/quickjs-android/src/main/c/java-object.h:
--------------------------------------------------------------------------------
1 | #ifndef QUICKJS_ANDROID_JAVA_OBJECT_H
2 | #define QUICKJS_ANDROID_JAVA_OBJECT_H
3 |
4 | #include
5 | #include
6 |
7 | int java_object_init_context(JSContext *ctx);
8 |
9 | JSValue QJ_NewJavaObject(JSContext *ctx, JNIEnv *env, jobject object);
10 |
11 | jobject QJ_GetJavaObject(JSContext *ctx, JSValueConst val);
12 |
13 | #endif //QUICKJS_ANDROID_JAVA_OBJECT_H
14 |
--------------------------------------------------------------------------------
/quickjs-android/src/main/java/com/shiqi/quickjs/ArrayTypeAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Hippo Seven
3 | * Copyright 2023-Present Shiqi Mei
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.shiqi.quickjs;
19 |
20 | import java.lang.reflect.Array;
21 | import java.lang.reflect.Type;
22 |
23 | class ArrayTypeAdapter extends TypeAdapter