1、首先看一下Android中webview的属性设置
//垂直不显示
this.setVerticalScrollBarEnabled(false);
//设置编码
this.getSettings().setDefaultTextEncodingName("utf-8");
//与JS交互必不可少的属性
this.getSettings().setJavaScriptEnabled(true);
this.getSettings().setDomStorageEnabled(true);
//支持JS打开新窗口
this.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
mStoreDetailJSObject = new StoreDetailJSObject(context);
//绑定JS操作对象
this.addJavascriptInterface(mStoreDetailJSObject, StoreDetailJSObject.JSOBJ_NAME);
this.getSettings().setSupportZoom(true);
//清理缓存
clearCache(true);
clearHistory();
this.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
this.getSettings().setPluginState(WebSettings.PluginState.ON);
//扩大比例的缩放
this.getSettings().setUseWideViewPort(true);
//自适应屏幕
this.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
this.getSettings().setLoadWithOverviewMode(true);
this.setOverScrollMode(OVER_SCROLL_NEVER);
this.setFadingEdgeLength(0);
2、JS调用原生代码
上面用到了addJavascriptInterface方法绑定与JS交互的对象,下面是StoreDetailJSObject类
public class StoreDetailJSObject {
private JSWebView webView;
private Context context;
public static final String JSOBJ_NAME = "JSCallDetail";
public StoreDetailJSObject(Context context){
this.context = context;
}
public StoreDetailJSObject(Context context, JSWebView webView){
this.context = context;
this.webView = webView;
}
/**
* 获取APP token
* @return
*/
@JavascriptInterface
public String getAppToken(){
if (!CenterObserver.getInstance().isLogin()){
context.startActivity(new Intent(context, LoginTrinityActivity.class));
}
return MyApplication.App.getToken();
}
/**
* 跳转原生界面
*/
@JavascriptInterface
public void appChannl(int id){
if (PhoneUtils.isFastDoubleClick()){
//连续点击
return;
}
Intent it = new Intent(context,MainActivity.class);
context.startActivity(it);
}
/**
* 调用电话拨号
*/
// @JavascriptInterface
// public void callTelServer(final String tel){
// AlertDialog.Builder builder = new AlertDialog.Builder(context);
// builder.setTitle(context.getResources().getString(R.string.tip_title));
// builder.setMessage(tel);
// builder.setNegativeButton(context.getResources().getString(R.string.cancel_dialog), null);
// builder.setPositiveButton(context.getResources().getString(R.string.text_call_tel),
// new DialogInterface.OnClickListener() {
//
// @Override
// public void onClick(DialogInterface arg0, int arg1) {
// Intent intent = new Intent(Intent.ACTION_CALL,
// Uri.parse("tel:" + tel));
// context.startActivity(intent);
// }
// });
// builder.show();
// }
}
上面的@JavascriptInterface标注是JS调用原生必不可少的
那么在JS中怎么调用这些方法呢,上面的类中关联了绑定对象名称这里叫JSCallDetail
so:
在JS中调用:JSCallDetail.getAppToken();即可
带参:JSCallDetail.appChannl(int id);传递参数给Android端
3、原生调用JS代码
a、通过loadUrl方法调用JS中的方法
webView.loadUrl("javascript:show('"+info+"')");
b、根据ID获取指定标签的属性
private void callJsCode() {
String js = "document.getElementById('can_share_url').value";
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
mWebView.evaluateJavascript(js, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
LogUtil.e("can_share_url = "+value);
}
});
}else{
String value = mWebView.callJsMethodOld(js);
}
}
代码中根据id为can_share_url获取对应标签的value属性的值在onReceiveValue方法中返回 不过使用evaluateJavascript方法调用JS代码只能在SDK版本为Build.VERSION_CODES.KITKAT(19,4.4)或者以上才行
那么在4.4以下就要使用反射来实现了:
/**
* 4.4之前通过java反射机制 调用JS
* @param script
* @return
*/
public String callJsMethodOld(String script){
try {
//由webview取到webviewcore
Field field_webviewcore = WebView.class.getDeclaredField("mWebViewCore");
field_webviewcore.setAccessible(true);
Object obj_webviewcore = field_webviewcore.get(this);
//由webviewcore取到BrowserFrame
Field field_BrowserFrame = obj_webviewcore.getClass().getDeclaredField("mBrowserFrame");
field_BrowserFrame.setAccessible(true);
Object obj_frame = field_BrowserFrame.get(obj_webviewcore);
//获取BrowserFrame对象的stringByEvaluatingJavaScriptFromString方法
Method method_stringByEvaluatingJavaScriptFromString = obj_frame.getClass().getMethod("stringByEvaluatingJavaScriptFromString", String.class);
//执行stringByEvaluatingJavaScriptFromString方法
Object obj_value = method_stringByEvaluatingJavaScriptFromString.invoke(obj_frame, script);
//返回执行结果
return String.valueOf(obj_value);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
同样的如果是调用JS方法:
String js = "show("+info+")";
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
mWebView.evaluateJavascript(js, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
LogUtil.e("value= "+value);
}
});
}else{
String value = mWebView.callJsMethodOld(js);
}
直接传入方法就行,这些调用都限制在APP内部操作
3、外部浏览器调转到App
a、使用原始方法
首先在AndroidManifest.xml的Activity下追加以下内容。
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="test.app" android:pathPrefix="/openwith"/>
</intent-filter>
那么在Html中
<a href="myapp://test.app/openwith?id=1">启动应用程序</a>
b、使用第三方jar包ActivityRouter (包含内部原生跳转)
基于apt技术,通过注解方式来实现URL打开Activity功能,并支持在WebView和外部浏览器使用,支持多级Activity跳转,支持Bundle、Uri参数注入并转换参数类型。
特点
支持注解方式、手动方式注册Activity。
支持注入Bundle、Uri的参数并转换格式。
支持多级跳转。
支持外部浏览器打开。
支持HTTP协议。
支持目标Activity的URL构造器访问。
支持多个Module。
接入:https://github.com/joyrun/ActivityRouter
JS中有一个小技巧判断调用内部JS打开原生还是调用外部连接打开APP
通过try catch来执行内部调用代码 如:JSCallDetail.getAppToken();
若调用失败会执行catch块,所以在catch中执行外部浏览器打开APP的连接
try{ JSCallDetail.getAppToken();
}catch{window.location.href="myapp://test.app/openwith?id="+id} 如果没有APP调转到下载连接...