Cordova 3.x 基礎(11) -- JS是如何呼叫本地API的?
阿新 • • 發佈:2019-02-04
Cordova應用基於Webview,所以後臺程式碼和js互動都是基於Webview(Webkit)的介面的。
Android:
@JavascriptInterface/WebView#addJavascriptInterface()
參考原始碼 ExposedJsApi.java
iOS :
UIWebViewDelegate/UIWebView#stringByEvaluatingJavaScriptFromString()
參考原始碼 CDVWebViewDelegate.m
以下以Android呼叫照相機為例,簡單說明一下呼叫及回撥過程。
(1)建立的過程
①新增外掛
引用 cordova plugin add org.apache.cordova.camera
在plugins的目錄下建立org.apache.cordova.camera資料夾,並將該Plugin的所有程式碼Copy進去,具體程式碼依賴關係都記錄在plugin.xml裡。
②建立Android工程
引用 cordova platform add android
從上邊的Plugin資料夾中把Java檔案和js檔案Copy到Android工程的相應的資料夾下。
其中CameraLauncher擴充套件自CordovaPlugin,而CordovaPlugin定義在platforms\android\CordovaLib中,它是Cordova的基礎框架程式碼。
(2)呼叫的過程(JS->Native)
①HTML中引入cordova.js
引用 <script type="text/javascript" src="cordova.js"></script>
先做初始化處理,後根據cordova_plugins.js載入所有plugin的js檔案。
②在deviceready事件中呼叫Camera
Js程式碼
③呼叫Camera.js的getPicture方法
assets\www\plugins\org.apache.cordova.camera\www\Camera.js
getPicture()
->
exec(successCallback, errorCallback, "Camera", "takePicture", args)
->
function androidExec(success, fail, service, action, args) ***cordova.js
->
var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson);
④調入Java的exec()方法
在CordovaWebView初期化的時候會根據Android的版本,將ExposedJsApi物件新增到CordovaWebView中。
this.addJavascriptInterface(exposedJsApi, "_cordovaNative");
所以nativeApiProvider.get()的時候會根據 _cordovaNative 物件是否存在來判斷是使用JavascriptInterface方式,還是使用prompt方式。
如果使用JavascriptInterface方式(Android 4.2以上版本),直接進入ExposedJsApi.java中定義了@JavascriptInterface標示的exec()方法 。
如果使用prompt方式,CordovaChromeClient.java中重寫了onJsPrompt()方法,來呼叫exposedJsApi.exec()。
prompt(argsJson, 'gap:'+JSON.stringify([service, action, callbackId]));
總之入口都是exposedJsApi.exec().
@JavascriptInterface
public String exec(String service, String action, String callbackId, String arguments)
->
pluginManager.exec(service, action, callbackId, arguments);
PluginManager根據service呼叫獲取到相應的CordovaPlugin
->
CameraLauncher.execute(String action, JSONArray args, CallbackContext callbackContext)
CameraLauncher根據action,這裡是“takePicture”做本地API呼叫。
->
takePicture()
->
new Intent("android.media.action.IMAGE_CAPTURE");
cordova.startActivityForResult()
呼叫CordovaInterface(CordovaActivity->Activity)的startActivityForResult
(3)回撥的過程(Native->JS)
①上述API呼叫成功後,在onActivityResult(CameraLauncher.java)設定結果
onActivityResult(int requestCode, int resultCode, Intent intent)
// Send Uri back to JavaScript for viewing image
this.callbackContext.success(uri.toString());
②退回到ExposedJsApi的exec()方法
jsMessageQueue.setPaused(false);
->
NativeToJsMessageQueue的onNativeToJsMessageAvailable()
->
sendMessageMethod = webViewCore.getClass().getDeclaredMethod("sendMessage", Message.class)
->
sendMessageMethod.invoke(webViewCore, execJsMessage)
③cordova.js中接收訊息
androidExec.processMessages(messages)
->
processMessage(message)
->
cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
呼叫定義好的成功或者失敗的JS回撥函式。(payload為回傳值)
以上就是完整的過程。
Android:
@JavascriptInterface/WebView#addJavascriptInterface()
參考原始碼 ExposedJsApi.java
iOS :
UIWebViewDelegate/UIWebView#stringByEvaluatingJavaScriptFromString()
參考原始碼 CDVWebViewDelegate.m
以下以Android呼叫照相機為例,簡單說明一下呼叫及回撥過程。
(1)建立的過程
①新增外掛
引用 cordova plugin add org.apache.cordova.camera
在plugins的目錄下建立org.apache.cordova.camera資料夾,並將該Plugin的所有程式碼Copy進去,具體程式碼依賴關係都記錄在plugin.xml裡。
②建立Android工程
引用 cordova platform add android
從上邊的Plugin資料夾中把Java檔案和js檔案Copy到Android工程的相應的資料夾下。
- platforms\android\src\org\apache\cordova\camera\CameraLauncher.java等
- platforms\android\assets\www\plugins\org.apache.cordova.camera\www\Camera.js等
其中CameraLauncher擴充套件自CordovaPlugin,而CordovaPlugin定義在platforms\android\CordovaLib中,它是Cordova的基礎框架程式碼。
(2)呼叫的過程(JS->Native)
①HTML中引入cordova.js
引用 <script type="text/javascript" src="cordova.js"></script>
先做初始化處理,後根據cordova_plugins.js載入所有plugin的js檔案。
②在deviceready事件中呼叫Camera
Js程式碼
- navigator.camera.getPicture(onSuccess, onFail,
- { quality: 50,
- allowEdit: true,
- destinationType: destinationType.DATA_URL });
③呼叫Camera.js的getPicture方法
assets\www\plugins\org.apache.cordova.camera\www\Camera.js
getPicture()
->
exec(successCallback, errorCallback, "Camera", "takePicture", args)
->
function androidExec(success, fail, service, action, args) ***cordova.js
->
var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson);
④調入Java的exec()方法
在CordovaWebView初期化的時候會根據Android的版本,將ExposedJsApi物件新增到CordovaWebView中。
this.addJavascriptInterface(exposedJsApi, "_cordovaNative");
所以nativeApiProvider.get()的時候會根據 _cordovaNative 物件是否存在來判斷是使用JavascriptInterface方式,還是使用prompt方式。
如果使用JavascriptInterface方式(Android 4.2以上版本),直接進入ExposedJsApi.java中定義了@JavascriptInterface標示的exec()方法 。
如果使用prompt方式,CordovaChromeClient.java中重寫了onJsPrompt()方法,來呼叫exposedJsApi.exec()。
prompt(argsJson, 'gap:'+JSON.stringify([service, action, callbackId]));
總之入口都是exposedJsApi.exec().
@JavascriptInterface
public String exec(String service, String action, String callbackId, String arguments)
->
pluginManager.exec(service, action, callbackId, arguments);
PluginManager根據service呼叫獲取到相應的CordovaPlugin
->
CameraLauncher.execute(String action, JSONArray args, CallbackContext callbackContext)
CameraLauncher根據action,這裡是“takePicture”做本地API呼叫。
->
takePicture()
->
new Intent("android.media.action.IMAGE_CAPTURE");
cordova.startActivityForResult()
呼叫CordovaInterface(CordovaActivity->Activity)的startActivityForResult
(3)回撥的過程(Native->JS)
①上述API呼叫成功後,在onActivityResult(CameraLauncher.java)設定結果
onActivityResult(int requestCode, int resultCode, Intent intent)
// Send Uri back to JavaScript for viewing image
this.callbackContext.success(uri.toString());
②退回到ExposedJsApi的exec()方法
jsMessageQueue.setPaused(false);
->
NativeToJsMessageQueue的onNativeToJsMessageAvailable()
->
sendMessageMethod = webViewCore.getClass().getDeclaredMethod("sendMessage", Message.class)
->
sendMessageMethod.invoke(webViewCore, execJsMessage)
③cordova.js中接收訊息
androidExec.processMessages(messages)
->
processMessage(message)
->
cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
呼叫定義好的成功或者失敗的JS回撥函式。(payload為回傳值)
以上就是完整的過程。