├── .gitignore
├── Js.iml
├── README.md
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── xfans
│ │ └── jsbridge
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── index.html
│ ├── jsapi.js
│ └── pic.jpg
│ ├── java
│ └── com
│ │ └── xfans
│ │ └── jsbridge
│ │ ├── api
│ │ ├── AndroidApi.java
│ │ └── CMD.java
│ │ ├── bridge
│ │ ├── AndroidJsBridge.java
│ │ ├── ContextQueue.java
│ │ ├── RequestContent.java
│ │ ├── Utils.java
│ │ ├── XfansActivityInterface.java
│ │ ├── XfansWebChromeClientBridge.java
│ │ ├── XfansWebView.java
│ │ └── XfansWebViewClientBridge.java
│ │ ├── sample
│ │ ├── MainActivity.java
│ │ └── TestActivity.java
│ │ └── widget
│ │ └── XfansBaseActivity.java
│ └── res
│ ├── drawable-hdpi
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ ├── activity_main.xml
│ └── activity_test.xml
│ ├── menu
│ └── menu_main.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | #built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Windows thumbnail db
19 | Thumbs.db
20 |
21 | # OSX files
22 | .DS_Store
23 |
24 | # Eclipse project files
25 | .classpath
26 | .project
27 |
28 | # Android Studio
29 | .idea
30 | #.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
31 | .gradle
32 | build/
--------------------------------------------------------------------------------
/Js.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Js-Android-bridge
2 | =================
3 | 更新日志:
4 | 2015/01/09:修改XfansWebView.java,AndroidJsBridge.java兼容4.4.
5 |
6 | js 调用android native方法。
7 |
8 | 如:
9 |
10 | 1. js调用android相机,拍照成功后异步返回图片路径。
11 |
12 | 2. url定义跳转Activity的路径,从html页面跳转到Activity。
13 |
14 | 3. 打电话,发短信等。
15 |
16 | 参考了部分开源项目,Cordova等。
17 |
18 | 该项目使用Gradle构建。
19 |
20 | ------------------
21 |
22 | ##js调用native方式:
23 |
24 | 1. prompt方式:
25 |
26 | js端:
27 |
28 | ```javascript
29 | callAndroidSync : function (cmd, args) {//同步调用 prompt 方式
30 | return prompt(cmd,args);
31 | }
32 | ```
33 |
34 | native端:
35 |
36 | ```Java
37 | @Override
38 | public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
39 | Log.d("XfanWebChromeClient",url+":"+ message+":"+ defaultValue+":"+ result);
40 | return androidApi.callAndroidSync(view, url, message, defaultValue ,result);
41 | }
42 | ```
43 | 2. JavascriptInterface方式:
44 |
45 | js端:
46 |
47 | ```javascript
48 | AndroidJsBridge.callNative(cmd,args,key)
49 | ```
50 |
51 | Native端:
52 |
53 | ```Java
54 | public void callNative( String cmd, String agrs, String key){
55 | Log.d("Api", cmd + ":" + agrs + ":" + key);
56 | RequestContent requestContent = new RequestContent(cmd, agrs, key, webView);
57 | ContextQueue.reqMap.put(key,requestContent);
58 | androidApi.callAndroidAsync(this, requestContent);
59 | }
60 | ```
61 |
62 | ##Native调用js
63 |
64 | 1. prompt方式:
65 |
66 | js端:
67 | ```javascript
68 | return prompt(cmd,args)
69 | ```
70 |
71 | Native端:
72 | ```Java
73 | result.confirm("callAndroidSync");
74 | ```
75 |
76 | 2. loadurl方式:
77 |
78 | js端:
79 | ```javascript
80 | function show(str){
81 | var doc = document.getElementById("cont");
82 | doc.innerHTML = str;
83 | }
84 | ```
85 | Native端:
86 | ```java
87 | webView.loadUrl("javascript:show('hello')")
88 | ```
89 |
90 |
91 | -------------
92 | ##使用该项目:
93 |
94 | 修改`AndroidApi.java`,`CMD.java`即可。
95 |
96 |
97 | -------------
98 | ##注意
99 |
100 | 未处理webview的安全问题。
101 |
102 | [WebView中接口隐患与手机挂马利用](http://drops.wooyun.org/papers/548 "WebView中接口隐患与手机挂马利用")
103 |
104 | -------------
105 | ##License
106 | Copyright 2016 xfans
107 |
108 | Licensed under the Apache License, Version 2.0 (the "License");
109 | you may not use this file except in compliance with the License.
110 | You may obtain a copy of the License at
111 |
112 | http://www.apache.org/licenses/LICENSE-2.0
113 |
114 | Unless required by applicable law or agreed to in writing, software
115 | distributed under the License is distributed on an "AS IS" BASIS,
116 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
117 | See the License for the specific language governing permissions and
118 | limitations under the License.
119 |
120 | Js-Android bridge
121 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
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 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 19
5 | buildToolsVersion "21.1.1"
6 | defaultConfig {
7 | applicationId "com.xfans.js"
8 | minSdkVersion 14
9 | targetSdkVersion 15
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 |
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | }
25 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in E:\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/xfans/jsbridge/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/assets/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
28 |
29 |
30 | test
31 |
33 |
35 |
36 | 
37 | tel:10010
38 | gonative
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/assets/jsapi.js:
--------------------------------------------------------------------------------
1 | var JsApi = {
2 | callback_success : {}, // 输出的结果成功时调用的方法
3 | callback_fail : {}, // 输出的结果失败时调用的方法
4 | callAndroidSync : function (cmd, args) {//同步调用 prompt 方式
5 | return prompt(cmd,args);
6 | },
7 | callAndroidAsync : function (cmd, args, success, fail) {//异步调用 addJavascriptInterface方式
8 | var strKey = new String(new Date().getTime()).substring(5,13);
9 | key = '5'+strKey;//防止第一位为0
10 | JsApi.callback_success[key] = success;
11 | JsApi.callback_fail[key] = fail;
12 | var doc = document.getElementById("cont");
13 | doc.innerHTML = key;
14 | AndroidJsBridge.callNative(cmd,args,key)
15 | },
16 | jsCallback : function (code,result, key) {
17 | if(code = 1){ //1 seccuss
18 | setTimeout( "JsApi.callback_success['" +key+"']('" + result + "')", 0);
19 | }else{
20 | setTimeout( "JsApi.callback_fail['" +key+"']('" + result + "')", 0);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/assets/pic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfans/Js-Android-bridge/99fd676b1f86b03e294396491944473716becf64/app/src/main/assets/pic.jpg
--------------------------------------------------------------------------------
/app/src/main/java/com/xfans/jsbridge/api/AndroidApi.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge.api;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.content.Context;
6 | import android.content.DialogInterface;
7 | import android.content.Intent;
8 | import android.net.Uri;
9 | import android.os.Environment;
10 | import android.provider.MediaStore;
11 | import android.util.Log;
12 | import android.view.KeyEvent;
13 | import android.webkit.JsPromptResult;
14 | import android.webkit.JsResult;
15 | import android.webkit.WebView;
16 |
17 | import com.xfans.jsbridge.bridge.AndroidJsBridge;
18 | import com.xfans.jsbridge.bridge.RequestContent;
19 | import com.xfans.jsbridge.bridge.Utils;
20 |
21 | import java.io.File;
22 |
23 | /**
24 | * Created by xfans on 2014/12/12.
25 | */
26 | public class AndroidApi {
27 |
28 | /**
29 | * 同步
30 | * @param webView
31 | * @param url
32 | *@param message
33 | * @param jsonStr
34 | * @param result @return
35 | */
36 | public boolean callAndroidSync(WebView webView, String url, String message, String jsonStr, JsPromptResult result) {
37 | result.confirm("callAndroidSync");
38 | return true;
39 | }
40 |
41 | /**
42 | * url调用
43 | * @param webView
44 | * @param url
45 | */
46 | public boolean callUrl(WebView webView, String url){
47 | Log.d("AndroidApi",url);
48 | if(url != null){
49 | Context context = webView.getContext();
50 | String args = url.substring(url.indexOf(":")+1,url.length());
51 | String cmdStr = url.substring(0,url.indexOf(":"));
52 | CMD cmd = Utils.getCmd(cmdStr);
53 | switch (cmd){
54 | case GONATIVE:
55 | goActivity(context, args);
56 | break;
57 | case TEL:
58 | goTel(url, context);
59 | break;
60 | case GEO:
61 | getGeo(url, context);
62 | break;
63 | case MAILTO:
64 | goMailTo(url,context);
65 | break;
66 | case SMS:
67 | goSms(url, context);
68 | break;
69 | case MARKET:
70 | goMarket(url, context);
71 | break;
72 | default:
73 | goOther(url, context);
74 | break;
75 | }
76 | }
77 | return true;
78 | }
79 |
80 | private void goOther(String url, Context context) {
81 | Intent intent = new Intent(Intent.ACTION_VIEW);
82 | intent.setData(Uri.parse(url));
83 | context.startActivity(intent);
84 | }
85 |
86 | private void goMarket(String url, Context context) {
87 | Intent intent = new Intent(Intent.ACTION_VIEW);
88 | intent.setData(Uri.parse(url));
89 | context.startActivity(intent);
90 | }
91 |
92 | private void goSms(String url, Context context) {
93 | Intent intent = new Intent(Intent.ACTION_VIEW);
94 | // Get address
95 | String address = null;
96 | int parmIndex = url.indexOf('?');
97 | if (parmIndex == -1) {
98 | address = url.substring(4);
99 | }
100 | else {
101 | address = url.substring(4, parmIndex);
102 |
103 | // If body, then set sms body
104 | Uri uri = Uri.parse(url);
105 | String query = uri.getQuery();
106 | if (query != null) {
107 | if (query.startsWith("body=")) {
108 | intent.putExtra("sms_body", query.substring(5));
109 | }
110 | }
111 | }
112 | intent.setData(Uri.parse("sms:" + address));
113 | intent.putExtra("address", address);
114 | intent.setType("vnd.android-dir/mms-sms");
115 | context.startActivity(intent);
116 | }
117 |
118 | private void goMailTo(String url, Context context) {
119 | Intent intent = new Intent(Intent.ACTION_VIEW);
120 | intent.setData(Uri.parse(url));
121 | context.startActivity(intent);
122 | }
123 |
124 | private void getGeo(String url, Context context) {
125 | Intent intent = new Intent(Intent.ACTION_VIEW);
126 | intent.setData(Uri.parse(url));
127 | context.startActivity(intent);
128 | }
129 |
130 | /**
131 | * 异步
132 | * @param androidJsBridge
133 | * @param requestContent
134 | */
135 | public void callAndroidAsync(AndroidJsBridge androidJsBridge, RequestContent requestContent) {
136 | Log.d("AndroidApi","callAndroidAsync:");
137 | if(requestContent != null && androidJsBridge != null){
138 | Context context = androidJsBridge.getWebView().getContext();
139 | String cmdStr = requestContent.getCmd();
140 | CMD cmd = Utils.getCmd(cmdStr);
141 | switch (cmd){
142 | case CAMERA:
143 | goCamera(context, requestContent);
144 | break;
145 | case PICTURE:
146 | goPicture(context, requestContent);
147 | break;
148 |
149 | case NULL:
150 | break;
151 | }
152 | }
153 | }
154 |
155 | /**
156 | * 打电话
157 | * @param url
158 | * @param context
159 | */
160 | private void goTel(String url, Context context) {
161 | Intent intent = new Intent(Intent.ACTION_DIAL);
162 | intent.setData(Uri.parse(url));
163 | context.startActivity(intent);
164 | }
165 | /**
166 | * 跳转页面
167 | * @param context
168 | * @param args
169 | */
170 | private void goActivity(Context context, String args) {
171 | Log.d("AndroidApi","goActivity: "+context.getPackageName()+":"+args);
172 | Intent intent = new Intent();
173 | intent.setClassName(context,args);
174 | context.startActivity(intent);
175 | }
176 |
177 | /**
178 | * 调用相册
179 | * @param context
180 | * @param requestContent
181 | */
182 | private void goPicture(Context context, RequestContent requestContent) {
183 | Log.d("AndroidApi","goPicture");
184 | Intent intent = new Intent(Intent.ACTION_PICK);
185 | intent.setType("image/*");
186 | intent.setAction(Intent.ACTION_GET_CONTENT);
187 | ((Activity)context).startActivityForResult(intent, Integer.parseInt(requestContent.getKey()));
188 | }
189 |
190 | /**
191 | * 调用相机
192 | * @param context
193 | * @param requestContent
194 | */
195 | private void goCamera(Context context, RequestContent requestContent) {
196 | Log.d("AndroidApi","goCamera");
197 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
198 | File file = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis()+".jpg");
199 | requestContent.setResult(file.toString());
200 | intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
201 | ((Activity)context).startActivityForResult(intent, Integer.parseInt(requestContent.getKey()));
202 | }
203 |
204 | /**
205 | * onJsAlert
206 | * @param view
207 | * @param url
208 | * @param message
209 | * @param result
210 | * @return
211 | */
212 | public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
213 | Context context = view.getContext();
214 | AlertDialog.Builder dlg = new AlertDialog.Builder(context);
215 | dlg.setMessage(message);
216 | dlg.setTitle("Alert");
217 | //Don't let alerts break the back button
218 | dlg.setCancelable(true);
219 | dlg.setPositiveButton(android.R.string.ok,
220 | new AlertDialog.OnClickListener() {
221 | public void onClick(DialogInterface dialog, int which) {
222 | result.confirm();
223 | }
224 | });
225 | dlg.setOnCancelListener(
226 | new DialogInterface.OnCancelListener() {
227 | public void onCancel(DialogInterface dialog) {
228 | result.cancel();
229 | }
230 | });
231 | dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
232 | //DO NOTHING
233 | public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
234 | if (keyCode == KeyEvent.KEYCODE_BACK)
235 | {
236 | result.confirm();
237 | return false;
238 | }
239 | else
240 | return true;
241 | }
242 | });
243 | dlg.create();
244 | dlg.show();
245 | return true;
246 | }
247 |
248 | /**
249 | * onJsConfirm
250 | * @param view
251 | * @param url
252 | * @param message
253 | * @param result
254 | * @return
255 | */
256 | public boolean onJsConfirm(WebView view, String url, String message,final JsResult result) {
257 | Context context = view.getContext();
258 | AlertDialog.Builder dlg = new AlertDialog.Builder(context);
259 | dlg.setMessage(message);
260 | dlg.setTitle("Confirm");
261 | dlg.setCancelable(true);
262 | dlg.setPositiveButton(android.R.string.ok,
263 | new DialogInterface.OnClickListener() {
264 | public void onClick(DialogInterface dialog, int which) {
265 | result.confirm();
266 | }
267 | });
268 | dlg.setNegativeButton(android.R.string.cancel,
269 | new DialogInterface.OnClickListener() {
270 | public void onClick(DialogInterface dialog, int which) {
271 | result.cancel();
272 | }
273 | });
274 | dlg.setOnCancelListener(
275 | new DialogInterface.OnCancelListener() {
276 | public void onCancel(DialogInterface dialog) {
277 | result.cancel();
278 | }
279 | });
280 | dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
281 | //DO NOTHING
282 | public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
283 | if (keyCode == KeyEvent.KEYCODE_BACK)
284 | {
285 | result.cancel();
286 | return false;
287 | }
288 | else
289 | return true;
290 | }
291 | });
292 | dlg.create();
293 | dlg.show();
294 | return true;
295 | }
296 | }
297 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xfans/jsbridge/api/CMD.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge.api;
2 |
3 | /**
4 | * Created by xfans on 2014/12/13.
5 | */
6 | public enum CMD {
7 | CAMERA,//相机
8 | PICTURE,//相册
9 | GONATIVE,//跳转到应用页面
10 | TEL,//电话uri
11 | NULL,//错误
12 | GEO,//地图
13 | MAILTO,//邮件
14 | SMS,//短信
15 | MARKET,//android市场
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xfans/jsbridge/bridge/AndroidJsBridge.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge.bridge;
2 |
3 | import android.app.Activity;
4 | import android.os.Build;
5 | import android.util.Log;
6 | import android.webkit.JavascriptInterface;
7 | import android.webkit.WebView;
8 |
9 | import com.xfans.jsbridge.api.AndroidApi;
10 |
11 | /**
12 | * Created by xfans on 2014/12/12.
13 | */
14 | public class AndroidJsBridge {
15 |
16 | private XfansWebView webView;
17 | private AndroidApi androidApi;
18 |
19 | public WebView getWebView() {
20 | return webView;
21 | }
22 |
23 | public AndroidJsBridge(XfansWebView webView, AndroidApi androidApi) {
24 | this.webView = webView;
25 | this.androidApi = androidApi;
26 | }
27 | @JavascriptInterface
28 | public void callNative( String cmd, String agrs, String key){
29 | Log.d("AndroidJsBridge", cmd + ":" + agrs + ":" + key);
30 | RequestContent requestContent = new RequestContent(cmd, agrs, key, webView);
31 | ContextQueue.reqMap.put(key,requestContent);
32 | androidApi.callAndroidAsync(this, requestContent);
33 | }
34 |
35 | /**
36 | * @param code 1 success other fail
37 | * @param result json
38 | */
39 | public void jsResult(String code, String result,String key) {
40 | if(ContextQueue.reqMap.size()>0){
41 | String js = "('" + code + "','" + result + "','" + key + "')";
42 | runJs(js);
43 | }else{
44 | String js = "('0','0','0')";
45 | runJs(js);
46 | }
47 | }
48 |
49 | /**
50 | * run js
51 | * @param jsStr like:javascript: JsApi.jsCallback('1','{name:"xfans"}','2')"
52 | */
53 | private void runJs(String jsStr){
54 | ((Activity)webView.getContext()).runOnUiThread(new RunJsRunnable(jsStr));
55 | }
56 |
57 | private class RunJsRunnable implements Runnable{
58 | private String jsStr;
59 |
60 | RunJsRunnable(String jsStr) {
61 | this.jsStr = jsStr;
62 | }
63 |
64 | @Override
65 | public void run() {
66 | Log.d("AndroidJsBridge", jsStr);
67 | loadUrlForVersion(jsStr);
68 | }
69 | }
70 | private void loadUrlForVersion(String jsStr) {
71 | //fix bugs: 1. loadUrl may hide keyboard when your focus in a input. 2. loadUrl cannot be called too often.
72 | if (Build.VERSION.SDK_INT keys = new ArrayDeque();
11 | public static Map reqMap = new HashMap();
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xfans/jsbridge/bridge/RequestContent.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge.bridge;
2 |
3 | import android.webkit.WebView;
4 |
5 | /**
6 | * Created by xfans on 2014/12/12.
7 | */
8 | public class RequestContent {
9 | private String cmd;
10 | private String args;
11 | private String key;
12 | private String result;
13 | private WebView webView;
14 |
15 | public RequestContent(String cmd, String args, String key, WebView webView) {
16 | this.cmd = cmd;
17 | this.args = args;
18 | this.key = key;
19 | this.webView = webView;
20 | }
21 |
22 | public String getResult() {
23 | return result;
24 | }
25 |
26 | public void setResult(String result) {
27 | this.result = result;
28 | }
29 |
30 | public WebView getWebView() {
31 | return webView;
32 | }
33 |
34 | public void setWebView(WebView webView) {
35 | this.webView = webView;
36 | }
37 |
38 | public String getCmd() {
39 | return cmd.toUpperCase();
40 | }
41 |
42 | public void setCmd(String cmd) {
43 | this.cmd = cmd;
44 | }
45 |
46 | public String getArgs() {
47 | return args;
48 | }
49 |
50 | public void setArgs(String args) {
51 | this.args = args;
52 | }
53 |
54 | public String getKey() {
55 | return key;
56 | }
57 |
58 | public void setKey(String key) {
59 | this.key = key;
60 | }
61 |
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xfans/jsbridge/bridge/Utils.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge.bridge;
2 |
3 | import android.util.Log;
4 |
5 | import com.xfans.jsbridge.api.CMD;
6 |
7 | /**
8 | * Created by xfans on 2014/12/13.
9 | * 工具类
10 | */
11 | public class Utils {
12 | /**
13 | * String to Enum
14 | * @param cmdStr
15 | * @return
16 | */
17 | public static CMD getCmd(String cmdStr) {
18 | Log.d("Utils", "cmdStr:"+cmdStr);
19 | CMD cmd = CMD.NULL;
20 | try {
21 | cmd = CMD.valueOf(cmdStr.toUpperCase());
22 | } catch (IllegalArgumentException e) {
23 | e.printStackTrace();
24 | }
25 | return cmd;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xfans/jsbridge/bridge/XfansActivityInterface.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge.bridge;
2 |
3 | import android.content.Intent;
4 |
5 | /**
6 | * Created by xfans on 2014/12/13.
7 | */
8 | public interface XfansActivityInterface {
9 | abstract void setWebView(XfansWebView webView);
10 | abstract void setActivity();
11 | abstract void onActivityResult(int requestCode, int resultCode, Intent data);
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xfans/jsbridge/bridge/XfansWebChromeClientBridge.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge.bridge;
2 |
3 | import android.util.Log;
4 | import android.webkit.JsPromptResult;
5 | import android.webkit.JsResult;
6 | import android.webkit.WebChromeClient;
7 | import android.webkit.WebView;
8 |
9 | import com.xfans.jsbridge.api.AndroidApi;
10 |
11 | /**
12 | * Created by xfans on 2014/12/11.
13 | * WebChromeClient
14 | */
15 | public class XfansWebChromeClientBridge extends WebChromeClient {
16 | private AndroidApi androidApi;
17 |
18 | public XfansWebChromeClientBridge(AndroidApi androidApi) {
19 | this.androidApi = androidApi;
20 | }
21 |
22 | @Override
23 | public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
24 | return androidApi.onJsAlert(view,url,message,result);
25 | }
26 |
27 | @Override
28 | public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
29 | Log.d("XfanWebChromeClient",url+":"+ message+":"+ defaultValue+":"+ result);
30 |
31 | return androidApi.callAndroidSync(view, url, message, defaultValue ,result);
32 | }
33 |
34 | @Override
35 | public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
36 | return androidApi.onJsConfirm(view, url, message, result);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xfans/jsbridge/bridge/XfansWebView.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge.bridge;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.annotation.TargetApi;
5 | import android.app.Activity;
6 | import android.content.Context;
7 | import android.os.Build;
8 | import android.os.Message;
9 | import android.util.AttributeSet;
10 | import android.util.Log;
11 | import android.webkit.ValueCallback;
12 | import android.webkit.WebView;
13 | import java.lang.reflect.Field;
14 | import java.lang.reflect.Method;
15 |
16 | /**
17 | * Created by xfans on 2014/12/13.
18 | */
19 | public class XfansWebView extends WebView {
20 | private Activity activity;
21 | Method sendMessageMethod;
22 | Object webViewCore;
23 | boolean initFailed = false;;
24 |
25 | public XfansWebView(Context context) {
26 | super(context);
27 | this.initReflection();
28 | }
29 |
30 | public XfansWebView(Context context, AttributeSet attrs) {
31 | super(context, attrs);
32 | this.initReflection();
33 | }
34 |
35 | public XfansWebView(Context context, AttributeSet attrs, int defStyle) {
36 | super(context, attrs, defStyle);
37 | this.initReflection();
38 | }
39 |
40 | public Activity getActivity() {
41 | return activity;
42 | }
43 |
44 | public void setActivity(Activity activity) {
45 | this.activity = activity;
46 | }
47 |
48 | @SuppressWarnings("rawtypes")
49 | private void initReflection() {
50 | Object webViewObject = this;
51 | Class webViewClass = WebView.class;
52 | try {
53 | Field f = webViewClass.getDeclaredField("mProvider");
54 | f.setAccessible(true);
55 | webViewObject = f.get(this);
56 | webViewClass = webViewObject.getClass();
57 | } catch (Throwable e) {
58 | // mProvider is only required on newer Android releases.
59 | }
60 |
61 | try {
62 | Field f = webViewClass.getDeclaredField("mWebViewCore");
63 | f.setAccessible(true);
64 | webViewCore = f.get(webViewObject);
65 | if (webViewCore != null) {
66 | sendMessageMethod = webViewCore.getClass().getDeclaredMethod("sendMessage", Message.class);
67 | sendMessageMethod.setAccessible(true);
68 | }
69 | } catch (Throwable e) {
70 | initFailed = true;
71 | Log.e("XfansWebView", "PrivateApiBridgeMode failed to find the expected APIs.", e);
72 | }
73 | }
74 |
75 | /**
76 | * 默认加载js方式
77 | * @param url
78 | */
79 | @Override
80 | public void loadUrl(String url) {
81 | Log.d("XfansWebView","url");
82 | super.loadUrl(url);
83 | }
84 |
85 | /**
86 | * 反射方式加载js
87 | * @param jsStr
88 | */
89 | public void loadUrlReflection(String jsStr) {
90 | Log.d("XfansWebView","loadUrlReflection:"+jsStr);
91 | if (sendMessageMethod == null && !initFailed) {
92 | initReflection();
93 | }
94 | Message execJsMessage = Message.obtain(null, 194, jsStr);//194?
95 | // webViewCore is lazily initialized, and so may not be available right away.
96 | if (sendMessageMethod != null) {
97 | try {
98 | sendMessageMethod.invoke(webViewCore, execJsMessage);
99 | } catch (Throwable e) {
100 | Log.e("XfansWebView", "Reflection message bridge failed.", e);
101 | }
102 | }
103 | }
104 | /**
105 | * 4.4新方法
106 | * @param jsStr
107 | */
108 | @SuppressLint("NewApi")
109 | public void evaJsForKitkat(String jsStr) {
110 | evaluateJavascript(jsStr,new ValueCallback() {
111 | @Override
112 | public void onReceiveValue(String s) {
113 | Log.d("AndroidJsBridge", "onReceiveValue:" + s);
114 | }
115 | });
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xfans/jsbridge/bridge/XfansWebViewClientBridge.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge.bridge;
2 |
3 | import android.util.Log;
4 | import android.webkit.WebView;
5 | import android.webkit.WebViewClient;
6 |
7 | import com.xfans.jsbridge.api.AndroidApi;
8 |
9 | /**
10 | * Created by xfans on 2014/12/13.
11 | */
12 | public class XfansWebViewClientBridge extends WebViewClient{
13 | private AndroidApi androidApi;
14 |
15 | public XfansWebViewClientBridge(AndroidApi androidApi) {
16 | this.androidApi = androidApi;
17 | }
18 |
19 | @Override
20 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
21 | Log.d("XfansWebViewClientBridge","shouldOverrideUrlLoading:"+url);
22 | if(url == null){return false; }
23 | return androidApi.callUrl(view,url);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xfans/jsbridge/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge.sample;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.view.Menu;
6 | import android.view.MenuItem;
7 | import android.view.View;
8 | import android.widget.Button;
9 |
10 | import com.xfans.jsbridge.R;
11 | import com.xfans.jsbridge.bridge.XfansWebView;
12 | import com.xfans.jsbridge.widget.XfansBaseActivity;
13 |
14 |
15 | public class MainActivity extends XfansBaseActivity {
16 | private XfansWebView webView;
17 | private Button button;
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_main);
22 | webView = (XfansWebView) findViewById(R.id.webView);
23 | button = (Button) findViewById(R.id.btn);
24 | setWebView(webView);
25 | button.setOnClickListener(new View.OnClickListener() {
26 | @Override
27 | public void onClick(View view) {
28 | Intent intent = new Intent();
29 | intent.setClassName(MainActivity.this,"com.xfans.js.sample.TestActivity");
30 | MainActivity.this.startActivity(intent);
31 | }
32 | });
33 | webView.loadUrl("file:///android_asset/index.html");
34 | }
35 |
36 | @Override
37 | public boolean onCreateOptionsMenu(Menu menu) {
38 | // Inflate the menu; this adds items to the action bar if it is present.
39 | getMenuInflater().inflate(R.menu.menu_main, menu);
40 | return true;
41 | }
42 |
43 | @Override
44 | public boolean onOptionsItemSelected(MenuItem item) {
45 | // Handle action bar item clicks here. The action bar will
46 | // automatically handle clicks on the Home/Up button, so long
47 | // as you specify a parent activity in AndroidManifest.xml.
48 | int id = item.getItemId();
49 |
50 | //noinspection SimplifiableIfStatement
51 | if (id == R.id.action_settings) {
52 | return true;
53 | }
54 | return super.onOptionsItemSelected(item);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xfans/jsbridge/sample/TestActivity.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge.sample;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 |
6 | import com.xfans.jsbridge.R;
7 |
8 | /**
9 | * Created by xfans on 2014/12/13.
10 | */
11 | public class TestActivity extends Activity {
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.activity_test);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xfans/jsbridge/widget/XfansBaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.xfans.jsbridge.widget;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 | import android.util.Log;
8 | import android.webkit.WebSettings;
9 |
10 | import com.xfans.jsbridge.api.AndroidApi;
11 | import com.xfans.jsbridge.api.CMD;
12 | import com.xfans.jsbridge.bridge.AndroidJsBridge;
13 | import com.xfans.jsbridge.bridge.ContextQueue;
14 | import com.xfans.jsbridge.bridge.RequestContent;
15 | import com.xfans.jsbridge.bridge.Utils;
16 | import com.xfans.jsbridge.bridge.XfansActivityInterface;
17 | import com.xfans.jsbridge.bridge.XfansWebChromeClientBridge;
18 | import com.xfans.jsbridge.bridge.XfansWebView;
19 | import com.xfans.jsbridge.bridge.XfansWebViewClientBridge;
20 |
21 | /**
22 | * Created by xfans on 2014/12/12.
23 | */
24 | public class XfansBaseActivity extends Activity implements XfansActivityInterface {
25 | private XfansWebView webView;
26 | private AndroidJsBridge androidJsBridge;
27 |
28 | @Override
29 | public void setWebView(XfansWebView webView){
30 | this.webView = webView;
31 | AndroidApi androidApi = new AndroidApi();
32 | androidJsBridge = new AndroidJsBridge(webView,androidApi);
33 | XfansWebChromeClientBridge xfansWebChromeClientBridge = new XfansWebChromeClientBridge(androidApi);
34 | XfansWebViewClientBridge xfansWebViewClientBridge = new XfansWebViewClientBridge(androidApi);
35 | WebSettings webSettings = webView.getSettings();
36 | webSettings.setJavaScriptEnabled(true);
37 | webView.addJavascriptInterface(androidJsBridge, "AndroidJsBridge");
38 | webView.setWebChromeClient(xfansWebChromeClientBridge);
39 | webView.setWebViewClient(xfansWebViewClientBridge);
40 | }
41 |
42 | @Override
43 | public void setActivity() {
44 | webView.setActivity(this);
45 | }
46 |
47 | @Override
48 | protected void onCreate(Bundle savedInstanceState) {
49 | super.onCreate(savedInstanceState);
50 | }
51 |
52 | @Override
53 | protected void onResume() {
54 | super.onResume();
55 | if(webView == null){
56 | try {
57 | throw new Exception("请先在onCreate中调用setWebView");
58 | } catch (Exception e) {
59 | e.printStackTrace();
60 | }
61 | }
62 | }
63 |
64 | @Override
65 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
66 | super.onActivityResult(requestCode, resultCode, data);
67 | Log.d("XfansBaseActivity","onActivityResult");
68 | if (resultCode != 0){
69 | RequestContent requestContent = ContextQueue.reqMap.get(requestCode+"");
70 | if(requestContent != null){
71 | String cmdStr = requestContent.getCmd();
72 | CMD cmd = Utils.getCmd(cmdStr);
73 | switch (cmd){
74 | case CAMERA:
75 | String path = requestContent.getResult();
76 | androidJsBridge.jsResult("1", path, requestCode + "");
77 | break;
78 | case PICTURE:
79 | Uri imageUri= data.getData();//TODO 解析正确路径
80 | androidJsBridge.jsResult("1", imageUri.getPath(), requestCode + "");
81 | break;
82 | case NULL:
83 | break;
84 | }
85 | }
86 | }else{
87 | androidJsBridge.jsResult("0","0","0");
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfans/Js-Android-bridge/99fd676b1f86b03e294396491944473716becf64/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfans/Js-Android-bridge/99fd676b1f86b03e294396491944473716becf64/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfans/Js-Android-bridge/99fd676b1f86b03e294396491944473716becf64/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfans/Js-Android-bridge/99fd676b1f86b03e294396491944473716becf64/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_test.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Js
5 | Hello world!
6 | Settings
7 | MainActivity
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/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 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.0.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfans/Js-Android-bridge/99fd676b1f86b03e294396491944473716becf64/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
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-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
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 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
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 Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------