├── .idea
└── workspace.xml
├── JavascriptInterface
├── .gitignore
├── .idea
│ ├── codeStyles
│ │ └── Project.xml
│ ├── gradle.xml
│ ├── misc.xml
│ ├── runConfigurations.xml
│ └── vcs.xml
├── app
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── javascriptinterface
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── assets
│ │ │ ├── JSBridge.js
│ │ │ └── index.html
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── javascriptinterface
│ │ │ │ ├── CallBack.java
│ │ │ │ ├── JSBridge.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── NativeMethods.java
│ │ └── res
│ │ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── drawable
│ │ │ └── ic_launcher_background.xml
│ │ │ ├── layout
│ │ │ └── activity_main.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── javascriptinterface
│ │ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
├── LICENSE
├── Prompt
├── .gitignore
├── .idea
│ ├── codeStyles
│ │ └── Project.xml
│ ├── gradle.xml
│ ├── misc.xml
│ ├── runConfigurations.xml
│ └── vcs.xml
├── app
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── prompt
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── assets
│ │ │ ├── JSBridge.js
│ │ │ └── index.html
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── prompt
│ │ │ │ ├── CallBack.java
│ │ │ │ ├── JSBridge.java
│ │ │ │ ├── JSBridgeChromeClient.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── NativeMethods.java
│ │ └── res
│ │ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── drawable
│ │ │ └── ic_launcher_background.xml
│ │ │ ├── layout
│ │ │ └── activity_main.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── prompt
│ │ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
├── README.md
├── UrlSchema
├── .gitignore
├── .idea
│ ├── codeStyles
│ │ └── Project.xml
│ ├── gradle.xml
│ ├── misc.xml
│ ├── runConfigurations.xml
│ └── vcs.xml
├── app
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── urlschema
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── assets
│ │ │ ├── JSBridge.js
│ │ │ └── index.html
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── urlschema
│ │ │ │ ├── CallBack.java
│ │ │ │ ├── JSBridge.java
│ │ │ │ ├── JSBridgeViewClient.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── NativeMethods.java
│ │ └── res
│ │ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── drawable
│ │ │ └── ic_launcher_background.xml
│ │ │ ├── layout
│ │ │ └── activity_main.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── urlschema
│ │ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
└── assets
├── addJavascriptInterface.png
├── evaluateJavascript.png
├── intercept-prompt.png
├── intercept-url.png
└── loadUrl.png
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/JavascriptInterface/.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 |
--------------------------------------------------------------------------------
/JavascriptInterface/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/JavascriptInterface/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
--------------------------------------------------------------------------------
/JavascriptInterface/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/JavascriptInterface/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/JavascriptInterface/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "com.example.javascriptinterface"
7 | minSdkVersion 19
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | compileOptions {
20 | sourceCompatibility = '1.8'
21 | targetCompatibility = '1.8'
22 | sourceCompatibility JavaVersion.VERSION_1_8
23 | targetCompatibility JavaVersion.VERSION_1_8
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(include: ['*.jar'], dir: 'libs')
29 | implementation 'com.android.support:appcompat-v7:28.0.0'
30 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
31 | testImplementation 'junit:junit:4.12'
32 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
33 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
34 | }
35 |
--------------------------------------------------------------------------------
/JavascriptInterface/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
22 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/androidTest/java/com/example/javascriptinterface/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.javascriptinterface;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.example.javascriptinterface", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/assets/JSBridge.js:
--------------------------------------------------------------------------------
1 | window.callbackId = 0;
2 |
3 | var bridge = {
4 | call: function(method, arg, cb) {
5 | var args = {
6 | data: arg === undefined ? null : JSON.stringify(arg),
7 | };
8 |
9 | if (typeof cb === 'function') {
10 | var cbName = 'CALLBACK' + window.callbackId++;
11 | window[cbName] = cb;
12 | args['cbName'] = cbName;
13 | }
14 |
15 | if (window._jsbridge) {
16 | window._jsbridge.call(method, JSON.stringify(args));
17 | }
18 | }
19 | };
20 |
21 | module.exports = bridge;
22 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/assets/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/java/com/example/javascriptinterface/CallBack.java:
--------------------------------------------------------------------------------
1 | package com.example.javascriptinterface;
2 |
3 | import android.webkit.ValueCallback;
4 | import android.webkit.WebView;
5 |
6 | import org.json.JSONObject;
7 |
8 | public class CallBack {
9 | private String cbName;
10 | private WebView mWebView;
11 |
12 | public CallBack(WebView webView, String cbName) {
13 | this.cbName = cbName;
14 | this.mWebView = webView;
15 | }
16 |
17 | public void apply(JSONObject jsonObject) {
18 | if (mWebView!=null) {
19 | mWebView.post(() -> {
20 | mWebView.evaluateJavascript("javascript:" + cbName + "(" + jsonObject.toString() + ")", new ValueCallback() {
21 | @Override
22 | public void onReceiveValue(String value) {
23 | return;
24 | }
25 | });
26 | });
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/java/com/example/javascriptinterface/JSBridge.java:
--------------------------------------------------------------------------------
1 | package com.example.javascriptinterface;
2 |
3 | import android.net.Uri;
4 | import android.util.Log;
5 | import android.webkit.JavascriptInterface;
6 | import android.webkit.WebView;
7 |
8 | import org.json.JSONObject;
9 |
10 | import java.lang.reflect.Method;
11 | import java.lang.reflect.Modifier;
12 | import java.util.HashMap;
13 | import java.util.Map;
14 |
15 | public class JSBridge {
16 | private WebView mWebView;
17 |
18 | public JSBridge(WebView webView) {
19 | this.mWebView = webView;
20 | }
21 |
22 |
23 | private static Map> exposeMethods = new HashMap<>();
24 |
25 | public static void register(String exposeName, Class> classz) {
26 | if (!exposeMethods.containsKey(exposeName)) {
27 | exposeMethods.put(exposeName, getAllMethod(classz));
28 | }
29 | }
30 |
31 | private static HashMap getAllMethod(Class injectedCls) {
32 | HashMap methodHashMap = new HashMap<>();
33 |
34 | Method[] methods = injectedCls.getDeclaredMethods();
35 |
36 | for (Method method: methods) {
37 | if(method.getModifiers()!=(Modifier.PUBLIC | Modifier.STATIC) || method.getName()==null) {
38 | continue;
39 | }
40 | Class[] parameters = method.getParameterTypes();
41 | if (parameters!=null && parameters.length==3) {
42 | if (parameters[0] == WebView.class && parameters[1] == JSONObject.class && parameters[2] == CallBack.class) {
43 | methodHashMap.put(method.getName(), method);
44 | }
45 | }
46 | }
47 |
48 | return methodHashMap;
49 | }
50 |
51 | @JavascriptInterface
52 | public String call(String methodName, String args) {
53 | try {
54 | JSONObject _args = new JSONObject(args);
55 | JSONObject arg = new JSONObject(_args.getString("data"));
56 | String cbName = _args.getString("cbName");
57 |
58 |
59 | if (exposeMethods.containsKey("JSBridge")) {
60 | HashMap methodHashMap = exposeMethods.get("JSBridge");
61 |
62 | if (methodHashMap!=null && methodHashMap.size()!=0 && methodHashMap.containsKey(methodName)) {
63 | Method method = methodHashMap.get(methodName);
64 |
65 | if (method!=null) {
66 | method.invoke(null, mWebView, arg, new CallBack(mWebView, cbName));
67 | }
68 | }
69 | }
70 | } catch (Exception e) {
71 | e.printStackTrace();
72 | }
73 |
74 |
75 | return null;
76 | }
77 | }
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/java/com/example/javascriptinterface/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.javascriptinterface;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.KeyEvent;
6 | import android.webkit.WebChromeClient;
7 | import android.webkit.WebView;
8 | import android.webkit.WebViewClient;
9 |
10 | public class MainActivity extends AppCompatActivity {
11 |
12 | private WebView mWebView;
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_main);
18 |
19 | mWebView = (WebView) findViewById(R.id.mWebView);
20 |
21 | // 设置 webViewClient 类
22 | mWebView.setWebViewClient(new WebViewClient());
23 |
24 | // 设置 webChromeClient 类
25 | mWebView.setWebChromeClient(new WebChromeClient());
26 |
27 | // 设置支持调用 JS
28 | mWebView.getSettings().setJavaScriptEnabled(true);
29 |
30 | mWebView.loadUrl("file:///android_asset/index.html");
31 |
32 | JSBridge.register("JSBridge", NativeMethods.class);
33 | mWebView.addJavascriptInterface(new JSBridge(mWebView), "_jsbridge");
34 | }
35 |
36 |
37 | // 通过拦截 onKeyDown 事件实现网页回退
38 | @Override
39 | public boolean onKeyDown(int keyCode, KeyEvent event) {
40 | if(keyCode == event.KEYCODE_BACK) {
41 | if (mWebView.canGoBack()) {
42 | mWebView.goBack();
43 | return true;
44 | }
45 | }
46 |
47 | return super.onKeyDown(keyCode, event);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/java/com/example/javascriptinterface/NativeMethods.java:
--------------------------------------------------------------------------------
1 | package com.example.javascriptinterface;
2 |
3 | import android.webkit.JavascriptInterface;
4 | import android.webkit.WebView;
5 | import android.widget.Toast;
6 |
7 | import org.json.JSONObject;
8 |
9 | public class NativeMethods {
10 | public static void showToast(WebView view, JSONObject arg, CallBack callBack) {
11 | String message = arg.optString("msg");
12 |
13 | Toast.makeText(view.getContext(), message, Toast.LENGTH_SHORT).show();
14 |
15 | if (callBack !=null) {
16 | try {
17 | JSONObject result = new JSONObject();
18 | result.put("msg", "js 调用 native 成功!");
19 | callBack.apply(result);
20 | } catch (Exception e) {
21 | e.printStackTrace();
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
20 |
21 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/JavascriptInterface/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/JavascriptInterface/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/JavascriptInterface/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/JavascriptInterface/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/JavascriptInterface/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/JavascriptInterface/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/JavascriptInterface/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/JavascriptInterface/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/JavascriptInterface/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/JavascriptInterface/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | JavascriptInterface
3 |
4 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/JavascriptInterface/app/src/test/java/com/example/javascriptinterface/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.javascriptinterface;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/JavascriptInterface/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 |
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.3.2'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 |
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/JavascriptInterface/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=-Xmx1536m
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 |
15 |
16 |
--------------------------------------------------------------------------------
/JavascriptInterface/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/JavascriptInterface/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/JavascriptInterface/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Mar 17 20:15:06 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
7 |
--------------------------------------------------------------------------------
/JavascriptInterface/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/JavascriptInterface/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/JavascriptInterface/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 mcuking
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Prompt/.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 |
--------------------------------------------------------------------------------
/Prompt/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Prompt/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Prompt/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Prompt/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Prompt/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Prompt/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Prompt/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "com.example.prompt"
7 | minSdkVersion 19
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | compileOptions {
20 | sourceCompatibility JavaVersion.VERSION_1_8
21 | targetCompatibility JavaVersion.VERSION_1_8
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(include: ['*.jar'], dir: 'libs')
27 | implementation 'com.android.support:appcompat-v7:28.0.0'
28 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
29 | testImplementation 'junit:junit:4.12'
30 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
31 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
32 | }
33 |
--------------------------------------------------------------------------------
/Prompt/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
22 |
--------------------------------------------------------------------------------
/Prompt/app/src/androidTest/java/com/example/prompt/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.prompt;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.example.prompt", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/assets/JSBridge.js:
--------------------------------------------------------------------------------
1 | window.callbackId = 0;
2 |
3 | var bridge = {
4 | call: function(method, arg, cb) {
5 | var args = {
6 | data: arg === undefined ? null : JSON.stringify(arg),
7 | };
8 |
9 | if (typeof cb === 'function') {
10 | var cbName = 'CALLBACK' + window.callbackId++;
11 | window[cbName] = cb;
12 | args['cbName'] = cbName;
13 | }
14 |
15 | var url = 'jsbridge://' + method + '?' + JSON.stringify(args);
16 |
17 | prompt(url);
18 | }
19 | };
20 |
21 | module.exports = bridge;
22 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/assets/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/java/com/example/prompt/CallBack.java:
--------------------------------------------------------------------------------
1 | package com.example.prompt;
2 |
3 | import android.util.Log;
4 | import android.webkit.ValueCallback;
5 | import android.webkit.WebView;
6 |
7 | import org.json.JSONObject;
8 |
9 | public class CallBack {
10 | private String cbName;
11 | private WebView mWebView;
12 |
13 | public CallBack(WebView webView, String cbName) {
14 | this.cbName = cbName;
15 | this.mWebView = webView;
16 | }
17 |
18 | public void apply(JSONObject jsonObject) {
19 | if (mWebView!=null) {
20 | mWebView.post(() -> {
21 | mWebView.evaluateJavascript("javascript:" + cbName + "(" + jsonObject.toString() + ")", new ValueCallback() {
22 | @Override
23 | public void onReceiveValue(String value) {
24 | return;
25 | }
26 | });
27 | });
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/java/com/example/prompt/JSBridge.java:
--------------------------------------------------------------------------------
1 | package com.example.prompt;
2 |
3 | import android.net.Uri;
4 | import android.webkit.WebView;
5 |
6 | import org.json.JSONObject;
7 |
8 | import java.lang.reflect.Method;
9 | import java.lang.reflect.Modifier;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | public class JSBridge {
14 |
15 | private static Map> exposeMethods = new HashMap<>();
16 |
17 | public static void register(String exposeName, Class> classz) {
18 | if (!exposeMethods.containsKey(exposeName)) {
19 | exposeMethods.put(exposeName, getAllMethod(classz));
20 | }
21 | }
22 |
23 | private static HashMap getAllMethod(Class injectedCls) {
24 | HashMap methodHashMap = new HashMap<>();
25 |
26 | Method[] methods = injectedCls.getDeclaredMethods();
27 |
28 | for (Method method: methods) {
29 | if(method.getModifiers()!=(Modifier.PUBLIC | Modifier.STATIC) || method.getName()==null) {
30 | continue;
31 | }
32 | Class[] parameters = method.getParameterTypes();
33 | if (parameters!=null && parameters.length==3) {
34 | if (parameters[0] == WebView.class && parameters[1] == JSONObject.class && parameters[2] == CallBack.class) {
35 | methodHashMap.put(method.getName(), method);
36 | }
37 | }
38 | }
39 |
40 | return methodHashMap;
41 | }
42 |
43 |
44 | public static String call(WebView webView, String urlString) {
45 |
46 | if (!urlString.equals("") && urlString!=null && urlString.startsWith("jsbridge")) {
47 | Uri uri = Uri.parse(urlString);
48 |
49 | String methodName = uri.getHost();
50 |
51 | try {
52 | JSONObject args = new JSONObject(uri.getQuery());
53 | JSONObject arg = new JSONObject(args.getString("data"));
54 | String cbName = args.getString("cbName");
55 |
56 |
57 | if (exposeMethods.containsKey("JSBridge")) {
58 | HashMap methodHashMap = exposeMethods.get("JSBridge");
59 |
60 | if (methodHashMap!=null && methodHashMap.size()!=0 && methodHashMap.containsKey(methodName)) {
61 | Method method = methodHashMap.get(methodName);
62 |
63 | if (method!=null) {
64 | method.invoke(null, webView, arg, new CallBack(webView, cbName));
65 | }
66 | }
67 | }
68 | } catch (Exception e) {
69 | e.printStackTrace();
70 | }
71 |
72 | }
73 | return null;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/java/com/example/prompt/JSBridgeChromeClient.java:
--------------------------------------------------------------------------------
1 | package com.example.prompt;
2 |
3 | import android.webkit.JsPromptResult;
4 | import android.webkit.WebChromeClient;
5 | import android.webkit.WebView;
6 |
7 | public class JSBridgeChromeClient extends WebChromeClient {
8 | @Override
9 | public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
10 | result.confirm(JSBridge.call(view, message));
11 | return true;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/java/com/example/prompt/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.prompt;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.KeyEvent;
6 | import android.webkit.WebView;
7 | import android.webkit.WebViewClient;
8 |
9 | public class MainActivity extends AppCompatActivity {
10 |
11 | private WebView mWebView;
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_main);
17 |
18 | mWebView = (WebView) findViewById(R.id.mWebView);
19 |
20 | // 设置 webViewClient 类
21 | mWebView.setWebViewClient(new WebViewClient());
22 |
23 | // 设置 webChromeClient 类
24 | mWebView.setWebChromeClient(new JSBridgeChromeClient());
25 |
26 | // 设置支持调用 JS
27 | mWebView.getSettings().setJavaScriptEnabled(true);
28 |
29 | mWebView.loadUrl("file:///android_asset/index.html");
30 |
31 | JSBridge.register("JSBridge", NativeMethods.class);
32 | }
33 |
34 | // 通过拦截 onKeyDown 事件实现网页回退
35 | @Override
36 | public boolean onKeyDown(int keyCode, KeyEvent event) {
37 | if(keyCode == event.KEYCODE_BACK) {
38 | if (mWebView.canGoBack()) {
39 | mWebView.goBack();
40 | return true;
41 | }
42 | }
43 |
44 | return super.onKeyDown(keyCode, event);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/java/com/example/prompt/NativeMethods.java:
--------------------------------------------------------------------------------
1 | package com.example.prompt;
2 |
3 | import android.webkit.WebView;
4 | import android.widget.Toast;
5 |
6 | import org.json.JSONObject;
7 |
8 | public class NativeMethods {
9 | public static void showToast(WebView view, JSONObject arg, CallBack callBack) {
10 | String message = arg.optString("msg");
11 |
12 | Toast.makeText(view.getContext(), message, Toast.LENGTH_SHORT).show();
13 |
14 | if (callBack !=null) {
15 | try {
16 | JSONObject result = new JSONObject();
17 | result.put("msg", "js 调用 native 成功!");
18 | callBack.apply(result);
19 | } catch (Exception e) {
20 | e.printStackTrace();
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
21 |
22 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/Prompt/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/Prompt/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/Prompt/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/Prompt/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/Prompt/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/Prompt/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/Prompt/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/Prompt/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/Prompt/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/Prompt/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Prompt
3 |
4 |
--------------------------------------------------------------------------------
/Prompt/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Prompt/app/src/test/java/com/example/prompt/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.prompt;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/Prompt/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 |
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.3.2'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 |
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/Prompt/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=-Xmx1536m
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 |
15 |
16 |
--------------------------------------------------------------------------------
/Prompt/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/Prompt/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/Prompt/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Mar 17 20:27:31 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
7 |
--------------------------------------------------------------------------------
/Prompt/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/Prompt/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/Prompt/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JSBridge
2 |
3 | A demo JSBridge based on android
4 |
5 | 本项目以 js 与 android 通信为例,讲解 JSBridge 实现原理,下面提到的方法在 iOS(UIWebview 或 WKWebview)均有对应方法。
6 |
7 | ## 1. native to js
8 |
9 | 两种 native 调用 js 方法,注意被调用的方法需要在 JS 全局上下文上
10 |
11 | #### loadUrl
12 |
13 | #### evaluateJavascript
14 |
15 | ### 1.1 loadUrl
16 |
17 |
18 |
19 | ```java
20 | mWebview.loadUrl("javascript: func()");
21 | ```
22 |
23 | ### 1.2 evaluateJavascript
24 |
25 |
26 |
27 | ```java
28 | mWebview.evaluateJavascript("javascript: func()", new ValueCallback() {
29 | @Override
30 | public void onReceiveValue(String value) {
31 | return;
32 | }
33 | });
34 | ```
35 |
36 | #### 上述两种 native 调用 js 的方式对比如下表:
37 |
38 | | 方式 | 优点 | 缺点 |
39 | | ------------------ | ------------------------------------- | ----------------------------------------- |
40 | | loadUrl | 兼容性好 | 1. 会刷新页面 2. 无法获取 js 方法执行结果 |
41 | | evaluateJavascript | 1. 性能好 2. 可获取 js 执行后的返回值 | 仅在安卓 4.4 以上可用 |
42 |
43 | ## 2. js to native
44 |
45 | 三种 js 调用 native 方法
46 |
47 | #### 拦截 Url Schema(假请求)
48 |
49 | #### 拦截 prompt alert confirm
50 |
51 | #### 注入 JS 上下文
52 |
53 | ### 2.1 拦截 Url Schema
54 |
55 |
56 |
57 | 即由 h5 发出一条新的跳转请求,native 通过拦截 URL 获取 h5 传过来的数据。
58 |
59 | 跳转的目的地是一个非法不存在的 URL 地址,例如:
60 |
61 | ```javascript
62 | "jsbridge://methodName?{"data": arg, "cbName": cbName}"
63 | ```
64 |
65 | 具体示例如下:
66 |
67 | ```javascript
68 | "jsbridge://openScan?{"data": {"scanType": "qrCode"}, "cbName": "handleScanResult"}"
69 | ```
70 |
71 | h5 和 native 约定一个通信协议,例如 jsbridge, 同时约定调用 native 的方法名 methodName 作为域名,以及后面带上调用该方法的参数 arg,和接收该方法执行结果的 js 方法名 cbName。
72 |
73 | 具体可以在 js 端封装相关方法,供业务端统一调用,代码如下:
74 |
75 | ```javascript
76 | window.callbackId = 0;
77 |
78 | function callNative(methodName, arg, cb) {
79 | const args = {
80 | data: arg === undefined ? null : JSON.stringify(arg),
81 | };
82 |
83 | if (typeof cb === 'function') {
84 | const cbName = 'CALLBACK' + window.callbackId++;
85 | window[cbName] = cb;
86 | args['cbName'] = cbName;
87 | }
88 |
89 | const url = 'jsbridge://' + methodName + '?' + JSON.stringify(args);
90 |
91 | ...
92 | }
93 | ```
94 |
95 | 以上封装中较为巧妙的是将用于接收 native 执行结果的 js 回调方法 cb 挂载到 window 上,并为防止命名冲突,通过全局的 callbackId 来区分,然后将该回调函数在 window 上的名字放在参数中传给 native 端。native 拿到 cbName 后,执行完方法后,将执行结果通过 native 调用 js 的方式(上面提到的两种方法),调用 cb 传给 h5 端(例如将扫描结果传给 h5)。
96 |
97 | 至于如何在 h5 中发起请求,可以设置 window.location.href 或者创建一个新的 iframe 进行跳转。
98 |
99 | ```javascript
100 | function callNative(methodName, arg, cb) {
101 | ...
102 |
103 | const url = 'jsbridge://' + method + '?' + JSON.stringify(args);
104 |
105 | // 通过 location.href 跳转
106 | window.location.href = url;
107 |
108 | // 通过创建新的 iframe 跳转
109 | const iframe = document.createElement('iframe');
110 | iframe.src = url;
111 | iframe.style.width = 0;
112 | iframe.style.height = 0;
113 | document.body.appendChild(iframe);
114 |
115 | window.setTimeout(function() {
116 | document.body.removeChild(iframe);
117 | }, 800);
118 | }
119 | ```
120 |
121 | native 会拦截 h5 发出的请求,当检测到协议为 jsbridge 而非普通的 http/https/file 等协议时,会拦截该请求,解析出 URL 中的 methodName、arg、 cbName,执行该方法并调用 js 回调函数。
122 |
123 | 下面以安卓为例,通过覆盖 WebViewClient 类的 shouldOverrideUrlLoading 方法进行拦截,android 端具体封装会在下面单独的板块进行说明。
124 |
125 | ```java
126 | import android.util.Log;
127 | import android.webkit.WebView;
128 | import android.webkit.WebViewClient;
129 |
130 | public class JSBridgeViewClient extends WebViewClient {
131 | @Override
132 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
133 | JSBridge.call(view, url);
134 | return true;
135 | }
136 | }
137 | ```
138 |
139 | #### 拦截 URL Schema 的问题
140 |
141 | - 连续发送时消息丢失
142 |
143 | 如下代码:
144 |
145 | ```javascript
146 | window.location.href = "jsbridge://callNativeNslog?{"data": "111", "cbName": ""}";
147 | window.location.href = "jsbridge://callNativeNslog?{"data": "222", "cbName": ""}";
148 | ```
149 |
150 | js 此时的诉求是在同一个运行逻辑内,快速的连续发送出 2 个通信请求,用客户端本身 IDE 的 log,按顺序打印 111,222,那么实际结果是 222 的通信消息根本收不到,直接会被系统抛弃丢掉。
151 |
152 | 原因:因为 h5 的请求归根结底是一种模拟跳转,跳转这件事情上 webview 会有限制,当 h5 连续发送多条跳转的时候,webview 会直接过滤掉后发的跳转请求,因此第二个消息根本收不到,想要收到怎么办?js 里将第二条消息延时一下。
153 |
154 | ```javascript
155 | //发第一条消息
156 | location.href = "jsbridge://callNativeNslog?{"data": "111", "cbName": ""}";
157 |
158 | //延时发送第二条消息
159 | setTimeout(500,function(){
160 | location.href = "jsbridge://callNativeNslog?{"data": "222", "cbName": ""}";
161 | });
162 | ```
163 |
164 | 但这并不能保证此时是否有其他地方通过这种方式进行请求,为系统解决此问题,js 端可以封装一层队列,所有 js 代码调用消息都先进入队列并不立刻发送,然后 h5 会周期性比如 500 毫秒,清空一次队列,保证在很快的时间内绝对不会连续发 2 次请求通信。
165 |
166 | - URL 长度限制
167 |
168 | 如果需要传输的数据较长,例如方法参数很多时,由于 URL 长度限制,仍以丢失部分数据。
169 |
170 | ### 2.2 拦截 prompt alert confirm
171 |
172 |
173 |
174 | 即由 h5 发起 alert confirm prompt,native 通过拦截 prompt 等获取 h5 传过来的数据。
175 |
176 | 因为 alert confirm 比较常用,所以一般通过 prompt 进行通信。
177 |
178 | 约定的传输数据的组合方式以及 js 端封装方法的可以类似上面的 拦截 URL Schema 提到的方式。
179 |
180 | ```javascript
181 | function callNative(methodName, arg, cb) {
182 | ...
183 |
184 | const url = 'jsbridge://' + method + '?' + JSON.stringify(args);
185 |
186 | prompt(url);
187 | }
188 | ```
189 |
190 | native 会拦截 h5 发出的 prompt,当检测到协议为 jsbridge 而非普通的 http/https/file 等协议时,会拦截该请求,解析出 URL 中的 methodName、arg、 cbName,执行该方法并调用 js 回调函数。
191 |
192 | 下面以安卓为例,通过覆盖 WebChromeClient 类的 onJsPrompt 方法进行拦截,android 端具体封装会在下面单独的板块进行说明。
193 |
194 | ```java
195 | import android.webkit.JsPromptResult;
196 | import android.webkit.WebChromeClient;
197 | import android.webkit.WebView;
198 |
199 | public class JSBridgeChromeClient extends WebChromeClient {
200 | @Override
201 | public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
202 | result.confirm(JSBridge.call(view, message));
203 | return true;
204 | }
205 | }
206 | ```
207 |
208 | 这种方式没有太大缺点,也不存在连续发送时信息丢失。不过 iOS 的 UIWebView 不支持该方式(WKWebView 支持)。
209 |
210 | ### 2.3 注入 JS 上下文
211 |
212 |
213 |
214 | 即由 native 将实例对象通过 webview 提供的方法注入到 js 全局上下文,js 可以通过调用 native 的实例方法来进行通信。
215 |
216 | 具体有安卓 webview 的 addJavascriptInterface,iOS UIWebview 的 JSContext,iOS WKWebview 的 scriptMessageHandler。
217 |
218 | 下面以安卓 webview 的 addJavascriptInterface 为例进行讲解。
219 |
220 | 首先 native 端注入实例对象到 js 全局上下文,代码大致如下,具体封装会在下面的单独板块进行讲解:
221 |
222 | ```java
223 | public class MainActivity extends AppCompatActivity {
224 |
225 | private WebView mWebView;
226 |
227 | @Override
228 | protected void onCreate(Bundle savedInstanceState) {
229 | super.onCreate(savedInstanceState);
230 | setContentView(R.layout.activity_main);
231 |
232 | mWebView = (WebView) findViewById(R.id.mWebView);
233 |
234 | ...
235 |
236 | // 将 NativeMethods 类下面的提供给 js 的方法转换成 hashMap
237 | JSBridge.register("JSBridge", NativeMethods.class);
238 |
239 | // 将 JSBridge 的实例对象注入到 js 全局上下文中,名字为 _jsbridge,该实例对象下有 call 方法
240 | mWebView.addJavascriptInterface(new JSBridge(mWebView), "_jsbridge");
241 | }
242 | }
243 |
244 | public class NativeMethods {
245 | // 用来供 js 调用的方法
246 | public static void methodName(WebView view, JSONObject arg, CallBack callBack) {
247 | }
248 | }
249 |
250 | public class JSBridge {
251 | private WebView mWebView;
252 |
253 | public JSBridge(WebView webView) {
254 | this.mWebView = webView;
255 | }
256 |
257 |
258 | private static Map> exposeMethods = new HashMap<>();
259 |
260 | // 静态方法,用于将传入的第二个参数的类下面用于提供给 javacript 的接口转成 Map,名字为第一个参数
261 | public static void register(String exposeName, Class> classz) {
262 | ...
263 | }
264 |
265 | // 实例方法,用于提供给 js 统一调用的方法
266 | @JavascriptInterface
267 | public String call(String methodName, String args) {
268 | ...
269 | }
270 | }
271 | ```
272 |
273 | 然后 h5 端可以在 js 调用 window.\_jsbridge 实例下面的 call 方法,传入的数据组合方式可以类似上面两种方式。具体代码如下:
274 |
275 | ```javascript
276 | window.callbackId = 0;
277 |
278 | function callNative(method, arg, cb) {
279 | let args = {
280 | data: arg === undefined ? null : JSON.stringify(arg)
281 | };
282 |
283 | if (typeof cb === 'function') {
284 | const cbName = 'CALLBACK' + window.callbackId++;
285 | window[cbName] = cb;
286 | args['cbName'] = cbName;
287 | }
288 |
289 | if (window._jsbridge) {
290 | window._jsbridge.call(method, JSON.stringify(args));
291 | }
292 | }
293 | ```
294 |
295 | #### 注入 JS 上下文的问题
296 |
297 | 以安卓 webview 的 addJavascriptInterface 为例,在安卓 4.2 版本之前,js 可以利用 java 的反射 Reflection API,取得构造该实例对象的类的內部信息,并能直接操作该对象的内部属性及方法,这种方式会造成安全隐患,例如如果加载了外部网页,该网页的恶意 js 脚本可以获取手机的存储卡上的信息。
298 |
299 | 在安卓 4.2 版本后,可以通过在提供给 js 调用的 java 方法前加装饰器 @JavascriptInterface,来表明仅该方法可以被 js 调用。
300 |
301 | #### 上述三种 js 调用 native 的方式对比如下表:
302 |
303 | | 方式 | 优点 | 缺点 |
304 | | ------------------------- | ------------------ | ------------------------------------------------------- |
305 | | 拦截 Url Schema(假请求) | 无安全漏洞 | 1. 连续发送时消息丢失 2. Url 长度限制,传输数据大小受限 |
306 | | 拦截 prompt alert confirm | 无安全漏洞 | iOS 的 UIWebView 不支持该方式 |
307 | | 注入 JS 上下文 | 官方提供,方便简捷 | 在安卓 4.2 以下有安全漏洞 |
308 |
309 | ## 3. 安卓端 java 的封装
310 |
311 | native 与 h5 交互部分的代码在上面已经提到了,这里主要是讲述 native 端如何封装暴露给 h5 的方法。
312 |
313 | 首先单独封装一个类 NativeMethods,将供 h5 调用的方法以公有且静态方法的形式写入。如下:
314 |
315 | ```java
316 | public class NativeMethods {
317 | public static void showToast(WebView view, JSONObject arg, CallBack callBack) {
318 | ...
319 | }
320 | }
321 | ```
322 |
323 | 接下来考虑如何在 NativeMethods 和 h5 之前建立一个桥梁,JSBridge 类因运而生。
324 | JSBridge 类下主要有两个静态方法 register 和 call。其中 register 方法是用来将供 h5 调用的方法转化成 Map 形式,以便查询。而 call 方法主要是用接收 h5 端的调用,分解 h5 端传来的参数,查找并调用 Map 中的对应的 Native 方法。
325 |
326 | #### JSBridge 类的静态方法 register
327 |
328 | 首先在 JSBridge 类下声明一个静态属性 exposeMethods,数据类型为 HashMap 。然后声明静态方法 register,参数有字符串 exposeName 和类 classz,将 exposeName 和 classz 的所有静态方法 组合成一个 map,例如:
329 |
330 | ```java
331 | {
332 | jsbridge: {
333 | showToast: ...
334 | openScan: ...
335 | }
336 | }
337 | ```
338 |
339 | 代码如下:
340 |
341 | ```java
342 | private static Map> exposeMethods = new HashMap<>();
343 |
344 | public static void register(String exposeName, Class> classz) {
345 | if (!exposeMethods.containsKey(exposeName)) {
346 | exposeMethods.put(exposeName, getAllMethod(classz));
347 | }
348 | }
349 | ```
350 |
351 | 由上可知我们需要定义一个 getAllMethod 方法用来将类里的方法转化为 HashMap 数据格式。在该方法里同样声明一个 HashMap,并将满足条件的方法转化成 Map,key 为方法名,value 为方法。
352 |
353 | 其中条件为 公有 public 静态 static 方法且第一个参数为 Webview 类的实例,第二个参数为 JSONObject 类的实例,第三个参数为 CallBack 类的实例。 (CallBack 是自定义的类,后面会讲到)
354 | 代码如下:
355 |
356 | ```java
357 | private static HashMap getAllMethod(Class injectedCls) {
358 | HashMap methodHashMap = new HashMap<>();
359 |
360 | Method[] methods = injectedCls.getDeclaredMethods();
361 |
362 | for (Method method: methods) {
363 | if(method.getModifiers()!=(Modifier.PUBLIC | Modifier.STATIC) || method.getName()==null) {
364 | continue;
365 | }
366 | Class[] parameters = method.getParameterTypes();
367 | if (parameters!=null && parameters.length==3) {
368 | if (parameters[0] == WebView.class && parameters[1] == JSONObject.class && parameters[2] == CallBack.class) {
369 | methodHashMap.put(method.getName(), method);
370 | }
371 | }
372 | }
373 |
374 | return methodHashMap;
375 | }
376 | ```
377 |
378 | #### JSBridge 类的静态方法 call
379 |
380 | 由于注入 JS 上下文和两外两种,h5 端传过来的参数形式不同,所以处理参数的方式略有不同。
381 | 下面以拦截 Prompt 的方式为例进行讲解,在该方式中 call 接收的第一个参数为 webView,第二个参数是 arg,即 h5 端传过来的参数。还记得拦截 Prompt 方式时 native 端和 h5 端约定的传输数据的方式么?
382 |
383 | ```javascript
384 | "jsbridge://openScan?{"data": {"scanType": "qrCode"}, "cbName":"handleScanResult"}"
385 | ```
386 |
387 | call 方法首先会判断字符串是否以 jsbridge 开头(native 端和 h5 端之间约定的传输数据的协议名),然后该字符串转成 Uri 格式,然后获取其中的 host 名,即方法名,获取 query,即方法参数和 js 回调函数名组合的对象。最后查找 exposeMethods 的映射,找到对应的方法并执行该方法。
388 |
389 | ```java
390 | public static String call(WebView webView, String urlString) {
391 |
392 | if (!urlString.equals("") && urlString!=null && urlString.startsWith("jsbridge")) {
393 | Uri uri = Uri.parse(urlString);
394 |
395 | String methodName = uri.getHost();
396 |
397 | try {
398 | JSONObject args = new JSONObject(uri.getQuery());
399 | JSONObject arg = new JSONObject(args.getString("data"));
400 | String cbName = args.getString("cbName");
401 |
402 |
403 | if (exposeMethods.containsKey("JSBridge")) {
404 | HashMap methodHashMap = exposeMethods.get("JSBridge");
405 |
406 | if (methodHashMap!=null && methodHashMap.size()!=0 && methodHashMap.containsKey(methodName)) {
407 | Method method = methodHashMap.get(methodName);
408 |
409 | if (method!=null) {
410 | method.invoke(null, webView, arg, new CallBack(webView, cbName));
411 | }
412 | }
413 | }
414 | } catch (Exception e) {
415 | e.printStackTrace();
416 | }
417 |
418 | }
419 | return null;
420 | }
421 | ```
422 |
423 | #### CallBack 类
424 |
425 | js 调用 native 方法成功后,native 有必要返回给 js 一些反馈,例如接口是否调用成功,或者 native 执行后的得到的数据(例如扫码)。所以 native 需要执行 js 回调函数。
426 |
427 | 执行 js 回调函数方式本质是 native 调用 h5 的 js 方法,方式仍旧是上面提到的两种方式 evaluateJavascript 和 loadUrl。简单来说可以直接将 js 的回调函数名传给对应的 native 方法,native 执行通过 evaluateJavascript 调用。
428 |
429 | 但为了统一封装调用回调的方式,我们可以定义一个 CallBack 类,在其中定义一个名为 apply 的静态方法,该方法直接调用 js 回调。
430 |
431 | 注意:native 执行 js 方法需要在主线程上。
432 |
433 | ```java
434 | public class CallBack {
435 | private String cbName;
436 | private WebView mWebView;
437 |
438 | public CallBack(WebView webView, String cbName) {
439 | this.cbName = cbName;
440 | this.mWebView = webView;
441 | }
442 |
443 | public void apply(JSONObject jsonObject) {
444 | if (mWebView!=null) {
445 | mWebView.post(() -> {
446 | mWebView.evaluateJavascript("javascript:" + cbName + "(" + jsonObject.toString() + ")", new ValueCallback() {
447 | @Override
448 | public void onReceiveValue(String value) {
449 | return;
450 | }
451 | });
452 | });
453 | }
454 | }
455 | }
456 | ```
457 |
458 | 到此为止,JSBridge 的大致原理都讲完了。但功能仍可再加完善,例如:
459 |
460 | native 执行 js 方法时,可接受 js 方法中异步返回的数据,比如在 js 方法中请求某个接口在返回数据。直接调用 webview 提供的 evaluateJavascript,在第二个参数的类 ValueCallback 的实例方法 onReceiveValue 并不能接收到 js 异步返回的数据。
461 |
462 | 后面有空 native 调用 js 方式会继续完善的,最后以一句古语互勉:
463 |
464 | 路漫漫其修远兮 吾将上下而求索
465 |
--------------------------------------------------------------------------------
/UrlSchema/.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 |
--------------------------------------------------------------------------------
/UrlSchema/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/UrlSchema/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/UrlSchema/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/UrlSchema/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/UrlSchema/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/UrlSchema/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/UrlSchema/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "com.example.urlschema"
7 | minSdkVersion 19
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | compileOptions {
20 | sourceCompatibility JavaVersion.VERSION_1_8
21 | targetCompatibility JavaVersion.VERSION_1_8
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(include: ['*.jar'], dir: 'libs')
27 | implementation 'com.android.support:appcompat-v7:28.0.0'
28 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
29 | testImplementation 'junit:junit:4.12'
30 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
31 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
32 | }
33 |
--------------------------------------------------------------------------------
/UrlSchema/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
22 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/androidTest/java/com/example/urlschema/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.urlschema;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.example.urlschema", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/assets/JSBridge.js:
--------------------------------------------------------------------------------
1 | window.callbackId = 0;
2 |
3 | var bridge = {
4 | call: function(method, arg, cb) {
5 | var args = {
6 | data: arg === undefined ? null : JSON.stringify(arg),
7 | };
8 |
9 | if (typeof cb === 'function') {
10 | var cbName = 'CALLBACK' + window.callbackId++;
11 | window[cbName] = cb;
12 | args['cbName'] = cbName;
13 | }
14 |
15 | var url = 'jsbridge://' + method + '?' + JSON.stringify(args);
16 |
17 | var iframe = document.createElement('iframe');
18 | iframe.src = url;
19 | iframe.style.width = 0;
20 | iframe.style.height = 0;
21 | document.body.appendChild(iframe);
22 |
23 | window.setTimeout(function() {
24 | document.body.removeChild(iframe);
25 | }, 800);
26 | }
27 | };
28 |
29 | module.exports = bridge;
30 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/assets/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/java/com/example/urlschema/CallBack.java:
--------------------------------------------------------------------------------
1 | package com.example.urlschema;
2 |
3 | import android.webkit.ValueCallback;
4 | import android.webkit.WebView;
5 |
6 | import org.json.JSONObject;
7 |
8 | public class CallBack {
9 | private String cbName;
10 | private WebView mWebView;
11 |
12 | public CallBack(WebView webView, String cbName) {
13 | this.cbName = cbName;
14 | this.mWebView = webView;
15 | }
16 |
17 | public void apply(JSONObject jsonObject) {
18 | if (mWebView != null) {
19 | mWebView.post(() -> {
20 | mWebView.evaluateJavascript("javascript:" + cbName + "(" + jsonObject.toString() + ")", new ValueCallback() {
21 | @Override
22 | public void onReceiveValue(String value) {
23 | return;
24 | }
25 | });
26 | });
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/java/com/example/urlschema/JSBridge.java:
--------------------------------------------------------------------------------
1 | package com.example.urlschema;
2 |
3 | import android.net.Uri;
4 | import android.util.Log;
5 | import android.webkit.WebView;
6 |
7 | import org.json.JSONObject;
8 |
9 | import java.lang.reflect.Method;
10 | import java.lang.reflect.Modifier;
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | public class JSBridge {
15 |
16 | private static Map> exposeMethods = new HashMap<>();
17 |
18 | public static void register(String exposeName, Class> classz) {
19 | if (!exposeMethods.containsKey(exposeName)) {
20 | exposeMethods.put(exposeName, getAllMethod(classz));
21 | }
22 | }
23 |
24 | private static HashMap getAllMethod(Class injectedCls) {
25 | HashMap methodHashMap = new HashMap<>();
26 |
27 | Method[] methods = injectedCls.getDeclaredMethods();
28 |
29 | for (Method method: methods) {
30 | if(method.getModifiers()!=(Modifier.PUBLIC | Modifier.STATIC) || method.getName()==null) {
31 | continue;
32 | }
33 | Class[] parameters = method.getParameterTypes();
34 | if (parameters!=null && parameters.length==3) {
35 | if (parameters[0] == WebView.class && parameters[1] == JSONObject.class && parameters[2] == CallBack.class) {
36 | methodHashMap.put(method.getName(), method);
37 | }
38 | }
39 | }
40 |
41 | return methodHashMap;
42 | }
43 |
44 |
45 | public static String call(WebView webView, String urlString) {
46 | if (!urlString.equals("") && urlString!=null && urlString.startsWith("jsbridge")) {
47 |
48 | Uri uri = Uri.parse(urlString);
49 |
50 | String methodName = uri.getHost();
51 |
52 | try {
53 | JSONObject args = new JSONObject(uri.getQuery());
54 | JSONObject arg = new JSONObject(args.getString("data"));
55 | String cbName = args.getString("cbName");
56 |
57 |
58 | if (exposeMethods.containsKey("JSBridge")) {
59 | HashMap methodHashMap = exposeMethods.get("JSBridge");
60 |
61 | if (methodHashMap!=null && methodHashMap.size()!=0 && methodHashMap.containsKey(methodName)) {
62 | Method method = methodHashMap.get(methodName);
63 |
64 | if (method!=null) {
65 | method.invoke(null, webView, arg, new CallBack(webView, cbName));
66 | }
67 | }
68 | }
69 | } catch (Exception e) {
70 | e.printStackTrace();
71 | }
72 |
73 | }
74 | return null;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/java/com/example/urlschema/JSBridgeViewClient.java:
--------------------------------------------------------------------------------
1 | package com.example.urlschema;
2 |
3 | import android.util.Log;
4 | import android.webkit.WebView;
5 | import android.webkit.WebViewClient;
6 |
7 | public class JSBridgeViewClient extends WebViewClient {
8 | @Override
9 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
10 | JSBridge.call(view, url);
11 | return true;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/java/com/example/urlschema/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.urlschema;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.KeyEvent;
6 | import android.webkit.WebChromeClient;
7 | import android.webkit.WebView;
8 |
9 | public class MainActivity extends AppCompatActivity {
10 |
11 | private WebView mWebView;
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_main);
17 |
18 | mWebView = (WebView) findViewById(R.id.mWebView);
19 |
20 | // 设置 webViewClient 类
21 | mWebView.setWebViewClient(new JSBridgeViewClient());
22 |
23 | // 设置 webChromeClient 类
24 | mWebView.setWebChromeClient(new WebChromeClient());
25 |
26 | // 设置支持调用 JS
27 | mWebView.getSettings().setJavaScriptEnabled(true);
28 |
29 | mWebView.loadUrl("file:///android_asset/index.html");
30 |
31 | JSBridge.register("JSBridge", NativeMethods.class);
32 | }
33 |
34 | // 通过拦截 onKeyDown 事件实现网页回退
35 | @Override
36 | public boolean onKeyDown(int keyCode, KeyEvent event) {
37 | if(keyCode == event.KEYCODE_BACK) {
38 | if (mWebView.canGoBack()) {
39 | mWebView.goBack();
40 | return true;
41 | }
42 | }
43 |
44 | return super.onKeyDown(keyCode, event);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/java/com/example/urlschema/NativeMethods.java:
--------------------------------------------------------------------------------
1 | package com.example.urlschema;
2 |
3 | import android.webkit.WebView;
4 | import android.widget.Toast;
5 |
6 | import org.json.JSONObject;
7 |
8 | public class NativeMethods {
9 | public static void showToast(WebView view, JSONObject arg, CallBack callBack) {
10 | String message = arg.optString("msg");
11 |
12 | Toast.makeText(view.getContext(), message, Toast.LENGTH_SHORT).show();
13 |
14 | if (callBack !=null) {
15 | try {
16 | JSONObject result = new JSONObject();
17 | result.put("msg", "js 调用 native 成功!");
18 | callBack.apply(result);
19 | } catch (Exception e) {
20 | e.printStackTrace();
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
21 |
22 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/UrlSchema/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/UrlSchema/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/UrlSchema/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/UrlSchema/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/UrlSchema/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/UrlSchema/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/UrlSchema/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/UrlSchema/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/UrlSchema/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/UrlSchema/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | UrlSchema
3 |
4 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/UrlSchema/app/src/test/java/com/example/urlschema/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.urlschema;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/UrlSchema/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 |
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.3.2'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 |
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/UrlSchema/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=-Xmx1536m
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 |
15 |
16 |
--------------------------------------------------------------------------------
/UrlSchema/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/UrlSchema/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/UrlSchema/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Mar 19 14:00:24 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
7 |
--------------------------------------------------------------------------------
/UrlSchema/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/UrlSchema/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/UrlSchema/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/assets/addJavascriptInterface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/assets/addJavascriptInterface.png
--------------------------------------------------------------------------------
/assets/evaluateJavascript.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/assets/evaluateJavascript.png
--------------------------------------------------------------------------------
/assets/intercept-prompt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/assets/intercept-prompt.png
--------------------------------------------------------------------------------
/assets/intercept-url.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/assets/intercept-url.png
--------------------------------------------------------------------------------
/assets/loadUrl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcuking/JSBridge/172e01add8b053e320c1f3f884391221726bbbc9/assets/loadUrl.png
--------------------------------------------------------------------------------