本文來自http://blog.csdn.net/liuxian13183/ ,引用必須註明出處!
H5交互的框架很多,如ReactNative、Weex等,也有直接用JsBridge和WebAppInterface的方式,至於用哪種實現方式,主要看業務複雜度以及重要性。
拍板Cordova原因如下:
1、支持Android、iOS、Sybian等主流手機操作系統
2、使用時間長,被衆多知名公司使用,踩過的坑足夠多,資料查找方便
3、總監自己比較熟悉,有助於支持項目快速推進。
總之技術選型完畢,大家就開始準備落實方案。
先去查一下官方介紹:http://cordova.axuer.com/docs/zh-cn/latest/guide/platforms/android/index.html
cordova安裝
要求:NodeJs
要求:Jdk64位
npm出現npm err windows_nt 6.1.7601錯誤
npm config set https-proxy null
npm config set strict-ssl false
npm install -g cnpm –registry=https://registry.npm.taobao.org
便利性在於:支持同步和異步調用(需要自己寫相關插件)
下載完之後,咱們把cordova加入項目
1、這部分代碼放入assets目錄:
2、這部分代碼加入依賴
3、把config.xml文件放在這裏
<?xml version='1.0' encoding='utf-8'?>
<widget xmlns:cdv="http://cordova.apache.org/ns/1.0" id="com.company.packagename" version="1.0.0"
xmlns="http://www.w3.org/ns/widgets">
<feature name="Whitelist">
<param name="android-package" value="org.apache.cordova.whitelist.WhitelistPlugin"/>
<param name="onload" value="true"/>
</feature>
<feature name="SyncService">
<param name="android-package" value="com.cordova.plugin.SyncServicePlugin"/>
<param name="onload" value="true"/>
</feature>
<feature name="AsyncService">
<param name="android-package" value="com.cordova.plugin.AsyncServicePlugin"/>
<param name="onload" value="true"/>
</feature>
<name>HelloWorld</name>
<description>
A sample Apache Cordova application that responds to the deviceready event.
</description>
<author email="[email protected]" href="http://cordova.io">
Apache Cordova Team
</author>
<content src="index.html"/>
<access origin="*"/>
<allow-intent href="http://*/*"/>
<allow-intent href="https://*/*"/>
<allow-intent href="tel:*"/>
<allow-intent href="sms:*"/>
<allow-intent href="mailto:*"/>
<allow-intent href="geo:*"/>
<allow-intent href="market:*"/>
<preference name="loglevel" value="DEBUG"/>
<preference name="errorUrl" value="file:///android_asset/client-local/500.html"/>
</widget>
重點有4,分別是packageName、syncServicePlugin(同步插件)、asyncServicePlugin(異步插件)和errorUrl
4、設置CordovaPlugin的shouldAllowNavigation的返回值爲true,否則H5調不到本地插件
5、寫插件實現功能
@Override
public boolean execute(String action, final String rawArgs, CallbackContext callbackContext)
throws JSONException {
if (action.equals("js_viewImageAction")) {
try {
JSONArray array = new JSONArray(rawArgs);
JSONObject args = array.optJSONObject(0);
JSONArray imgArray = args.optJSONArray("img");
int index = args.optInt("index");
String[] target = new String[imgArray.length()];
for (int i = 0; i < imgArray.length(); i++) {
target[i] = imgArray.getString(i);
}
Intent intent = new Intent(cordova.getActivity(), ImageViewActivity.class);
intent.putExtra(IntentConstants.IMAGE_URLS, target);
intent.putExtra(IntentConstants.IMAGE_INDEX, index);
cordova.getActivity().startActivity(intent);
callbackContext.success();
return true;
} catch (Exception e) {
Logger.t(TAG).e("js_viewImageAction failed" + e);
}
}
return super.execute(action, rawArgs, callbackContext);
}
js_viewImageAction即插件名字。
通過JsonArray(據說iOS無法使用json傳數據),獲得json傳遞數據(注意要調callbackContext.success方法,使h5能確認native已經接收到;當然也可以用success方法回傳json結果數據),同時return true 代碼插件已被處理,不必再分發。
注意點:插件每次進入都會被初始化。
後面打算再插入一點WebView的知識點:
WebView狀態管理
//激活WebView爲活躍狀態,能正常執行網頁的響應
webView.onResume() ;
//當頁面被失去焦點被切換到後臺不可見狀態,需要執行onPause
//通過onPause動作通知內核暫停所有的動作,比如DOM的解析、plugin的執行、JavaScript執行。
webView.onPause();
//當應用程序(存在webview)被切換到後臺時,這個方法不僅僅針對當前的webview而是全局的全應用程序的webview
//它會暫停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
webView.pauseTimers()
//恢復pauseTimers狀態
webView.resumeTimers();
//銷燬Webview
//在關閉了Activity時,如果Webview的音樂或視頻,還在播放。就必須銷燬Webview
//但是注意:webview調用destory時,webview仍綁定在Activity上
//這是由於自定義webview構建時傳入了該Activity的context對象
//因此需要先從父容器中移除webview,然後再銷燬webview:
rootLayout.removeView(webView);
webView.destroy();
Js交互,4.4以上
// 只需要將第一種方法的loadUrl()換成下面該方法即可
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//此處爲 js 返回的結果
}
});
}
加載速度:使用本地資源(來源於隨時服務端推送)
public class MainActivity extends AppCompatActivity {
WebView mWebview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebview = (WebView) findViewById(R.id.webview);
// 創建WebView對象
mWebview.getSettings().setJavaScriptEnabled(true);
// 支持與JS交互
mWebview.loadUrl("http://ip.cn/");
// 加載需要顯示的網頁
mWebview.setWebViewClient(new WebViewClient() {
// 複寫shouldInterceptRequest
//API21以下用shouldInterceptRequest(WebView view, String url)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
// 步驟1:判斷攔截資源的條件,即判斷url裏的圖片資源的文件名
// 此處網頁裏圖片的url爲:http://s.ip-cdn.com/img/logo.gif
// 圖片的資源文件名爲:logo.gif
if (url.contains("logo.gif")) {
InputStream is = null;
// 步驟2:創建一個輸入流
try {
is =getApplicationContext().getAssets().open("images/error.png");
// 步驟3:打開需要替換的資源(存放在assets文件夾裏)
// 在app/src/main下創建一個assets文件夾
// assets文件夾裏再創建一個images文件夾,放一個error.png的圖片
} catch (IOException e) {
e.printStackTrace();
}
// 步驟4:替換資源
WebResourceResponse response = new WebResourceResponse("image/png",
"utf-8", is);
// 參數1:http請求裏該圖片的Content-Type,此處圖片爲image/png
// 參數2:編碼類型
// 參數3:替換資源的輸入流
System.out.println("舊API");
return response;
}
return super.shouldInterceptRequest(view, url);
}
// API21以上用shouldInterceptRequest(WebView view, WebResourceRequest request)
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
// 步驟1:判斷攔截資源的條件,即判斷url裏的圖片資源的文件名
// 此處圖片的url爲:http://s.ip-cdn.com/img/logo.gif
// 圖片的資源文件名爲:logo.gif
if (request.getUrl().toString().contains("logo.gif")) {
InputStream is = null;
// 步驟2:創建一個輸入流
try {
is = getApplicationContext().getAssets().open("images/error.png");
// 步驟3:打開需要替換的資源(存放在assets文件夾裏)
// 在app/src/main下創建一個assets文件夾
// assets文件夾裏再創建一個images文件夾,放一個error.png的圖片
} catch (IOException e) {
e.printStackTrace();
}
//步驟4:替換資源
WebResourceResponse response = new WebResourceResponse("image/png",
"utf-8", is);
// 參數1:http請求裏該圖片的Content-Type,此處圖片爲image/png
// 參數2:編碼類型
// 參數3:存放着替換資源的輸入流(上面創建的那個)
return response;
}
return super.shouldInterceptRequest(view, request);
}
});
}
}
安全方面:
禁用file協議及相關js調用
// 需要使用 file 協議
setAllowFileAccess(true);
setAllowFileAccessFromFileURLs(false);//true,則可從file裏的js,讀取本地私密源
setAllowUniversalAccessFromFileURLs(false);//true,則可從file裏的js,讀取所有源
// 禁止 file 協議加載 JavaScript
if (url.startsWith("file://") {
setJavaScriptEnabled(false);
} else {
setJavaScriptEnabled(true);
}
3.0以下刪除WebView內置導出的“searchBoxJavaBridge_”、“accessibility
”、“accessibilityTraversal”
更多WebView知識點:https://www.jianshu.com/p/3c94ae673e2a
有問題歡迎評論!