app中的webview通识篇(上)

前言

若是你仍是第一次与app合做开发webview的页面,那么对于如何调试,可能有哪些问题多是不够了解的。本文尝试性的根据本身的经验给你们一个入门级别的了解,若是是大佬级别的,能够绕路了。javascript

webview协议约定

为了更好的在app中调试开发咱们的移动页面(h5),咱们须要与app开发人员约定一些基本的原则,来保证咱们的页面能够很好的进行调试,包括调试工具、灵活的模拟上线时的app环境、测试交互过程当中的问题、方便自定义的修改成本身的h5地址等。前端

如下的方案仅供参考,每一条都是有实际用途的,若是公司里的webview须要进行准确的调试和后续开发,必要性的须要考虑如下的问题。java

主题 方案 备注
统一肯定的ua标识 好比ua结尾加入【xxx】
h5公用的app头 app端提供统一的app头,参考支付宝以及微信的ua交互,提供显示页面标题,返回,关闭的简单操做,默认页面可滚动 以后其余的h5默认在这个类浏览器外壳中,针对前端一些固定布局的方案,须要优化完善这个外壳,前端技改时间容许的话,最好给出完整肯定的方案能够在webview中无缝对接和展现
h5与app定制头 针对产品以及交互特殊需求,提供的特殊页面,好比单页,强交互逻辑页定制专门的头 须要产品明确说明特殊性,不是浏览器的返回,好比返回须要加确认框,就须要定制
h5与app功能性交互 约定常规交互方法的格式,并给出相互通信的一些固定的可用的方法,好比获取用户信息,获取app网络状态 这个是双向的功能性交互,h5的一些方法也能够设置app的状态,页面跳转,数据存储等
h5与app纯交互性方法 调取相应app的加载框,加载失败,相册控件,扫码控件 须要与产品,交互统一肯定是否使用app原生控件仍是h5效果。
h5与app不一样场景的分享互通 好比:用户在不一样app中:app分享到h5详情页,h5详情页也能够对应到app中打开 须要约定规则
app提供webview的外壳 能够经过app外壳扫码进入webview场景,模拟交互,开发阶段暴露解决一些app中问题 以上的app解决方案集成在这个app外壳中

关于 app内webiew与h5通信状况

做为常识咱们知道,通常状况下webview的页面是包括两种状况的,一种是原本就可能限定于只有app会嵌入的h5页面,这部分在与app进行通信的时候,咱们更多的是经过约定jsBridge的方式。一种是普通的h5页面。ios

jsBridge说的更直白一点,就是网页在载入时,向页面内注入一个指定的js文件,而后页面内就会有一个前端和app都知道的方法,经过这个方法前端能够唤起app的交互控件,甚至是跳转到其余的app页面,也能够知道app此时的一些设备状态、网络状态、用户信息等。而app也能够经过h5知道此时页面的状态,进而根据须要作能够在必要时唤起想要的操做。git

而另外一方面,webview也可看作一个普通的浏览器,能够载入任何的页面,因此咱们非app的内嵌页的h5也能够在app内经过webview进行打开; 而app外的h5能够经过app自定义的协议码来唤起app。github

相关的通信技术点可见下面的简陋的图说明。web

jsBridge参考文档

iOS与H5交互说明(ios)

iOS与H5交互,采用是JavaScriptCore方式。原理是iOS端在WebView加载完一个URL连接的时候,手动向H5页面绑定一个JSContext对象。利用这个JSContext对象,能够实现OC与JS间的双向交互。注意:JSContext对象是在iOS的webViewDidFinishLoad:回调里完成绑定的,在完成绑定前没法使用JS与OC的任何交互。objective-c

JS调用OC接口

JS开始调用OC接口前,有几个前提条件:

  • js的window.isReady方法已经触发过了,JS才能调用OC提供的方法。缘由是iOS会在JSContext对象绑定成功后,才会向js端调用isReady方法,因此js只有等isReady触发了,才能经过JSContext调用OC方法。chrome

  • iOS在绑定JSContext对象的时候,要约定好一个字段,而后OC会将原生方法注册到网页window对象的这个字段上。好比window.appjson

  • js端若是要异步接收原生方法的返回结果,须要在全局做用域内定义好回调方法

JS示例代码:

js调用OC原生方法,同步获取用户基本信息

// 约定好获取用户信息接口注册到window的app属性上
// getUserInfo方法是一个同步方法,能够js端能够直接获取到返回值
// 返回的对象能够是json字符串
var info = window.app.getUserInfo()
复制代码

js调用OC原生方法,拍照上传做业图片,并异步获取上传结果

// 假设约定好做业相关的OC接口都注册到window的homework属性上
window.homework.uploadHomeworkPicture(questionID)

// 在全局做用域内定义好回调方法,用于接收返回值
// 原生方法会在上传完做业图片的时候,间接调用该回调方法
function homeworkPictureDidUploaded(questionID, picUrl) {
  	// do something...
}
复制代码

JS里调用通用原生接口:

/** 跳转到课程详情 @param productId 商品ID(string类型) */
app.gotoCourseDetail(productId);

/** 关闭当前页面 */
app.finish();

/** 获取用户信息,已json字符串形式返回。主要字段以下: memberId: 用户id token: 用户登陆惟一标识 memberType: 用户类型 */
app.getUserInfo();

/** toast提示 @param msg 提示语(string类型) */
app.toast(msg);

/** 显示对话框 @param title 标题(string字符串) @param msg 消息(string字符串) @param actions 点击事件(一个json数组字符串),每一个数组元素字段以下: title: 事件标题(string字符串,好比“取消”) callback: 事件的js回调方法(string字符串) 示例: var actions = "[{'title': '取消', 'callback': 'cancelPay'}, {'title': '肯定', 'callback': 'confirmPay'}]"; app.confirm("舒适提示", "是否支付订单?", actions); */
app.confirm(title, msg, actions);
复制代码

OC调用JS接口

OC在调用JS方法时的注意事项:

  • js方法应该申明到全局做用域内,不然OC获取不到该方法

  • 若是在webViewDidFinishLoad:直接用过JSContext调用js方法,可能会出现调用无效的请求。为了不此类问题,推荐以setTimeout方式调用js方法

示例代码:

OC在webViewDidFinishLoad:中调用js的isReady方法

// setTimeout是JS的自带方法
// 这里使用setTimeout的目的是为了将isReady方法放到js调用队列的最后
JSValue *isReadyFunc = self.jsContext[@"isReady"];
if (isReadyFunc) {
	[self.jsContext[@"setTimeout"] callWithArguments:@[isReadyFunc, @100]];
}
复制代码

OC在JS发起的原生方法中调用js的setUserInfo方法

// 注意,JavaScriptCore支持NSDictionary、NSArray类型做参数传给js方法
NSDictionary *userInfo = ...;
[self.jsContext[@"setUserInfo"] callWithArguments:@[userInfo]];
复制代码

JS提供给原生调用的通用接口定义:

/** iOS原生初始化完成后调用本方法,告诉js已经准备好了 */ 
function isReady();

/** * return boolean 类型返回值: true h5已经处理了返回,native不处理; false h5没有处理返回,native直接返回上级原生页面 */
function gobackIfNeeded();
复制代码

APP唤醒

定义scheme: com.xxx.app

UserAgent

WebView的默认UserAgent为:"xxxx XXX/1.3.0", 其中xxxx为系统默认UserAgent。''/''后为app版本号

内嵌H5页面的加载(安卓)

1.原生提供一个框架页面给H5页面。框架只提供一个叫InnerWeb的类(这点js不须要知晓).如何须要在本地加载一个纯H5的内嵌页面,请使用IntentHelper.startWeb(Context context, String url)方法去载入一个内嵌H5页面。具体内部只是加载这个url。以后的逻辑都交给H5处理。

Android本地经过Java调用HTML页面中的JavaScript方法

原生调用js方法分一下两种类型的方法:

  1. 无返回值方法
  2. 有返回值方法

调用js中无返回值方法

很简单,咱们直接调用便可具体代码示例以下:

/** * f1 为js中声明的函数 */
mWebView.loadUrl("javascript:f1()");
复制代码

这样就能够调用js的方法了。

调用js中有返回值的方法

稍微复杂一点,以下:

/** * sum 为js中定义的函数 */
mWebView.evaluateJavascript("sum(1,2)", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String value) {
            Log.e(TAG, "onReceiveValue value=" + value);
        }
    });
复制代码

js调用Android本地Java方法

本地提供给js调用的映射对象,这须要注入,咱们同一使用一个叫app的对象。js如要调用本地方法。都以此开头来表明咱们原生方法。

具体以下:

<script type="text/javascript">
     function s(){
     // 注意下面的‘app’
    var result = window.app.gotoLogin();
    document.getElementById("p").innerHTML = result;
    }
</script>
复制代码

本地代码以下:

public calss AppJavascriptInterface {

  	@JavascriptInterface
  	public void gotoLogin() {
        if (mContext.get() == null) {
            Log.w("web", "页面已关闭");
            return;
        }
        LoginActivity.start(mContext.get());
    }
}
复制代码

产品协议

协议的主要以原生提供给H5的为主, 下面是我详细罗列的:

/** * 跳转登陆 */
@JavascriptInterface
public void gotoLogin();
/** * 跳转课程详情 */
@JavascriptInterface
public void gotoCourseDetail();
/** * 关闭当前页面 */
@JavascriptInterface
public void finish();
/** * 关闭当前页面获取当前用户信息,若是为空,说明用户未登陆 * * 目前有以下信息(以json格式返回给H5): * memberId: 用户id * token: 用户登陆惟一标识 * memberType: 用户类型 */
@JavascriptInterface
public String getUserInfo();

/** * 返回 * * 目前有以下信息(以json格式返回给H5): * memberId: 用户id * token: 用户登陆惟一标识 * memberType: 用户类型 */
public void back();

/** * */
public void toast(String msg);

public void confirm(String title, String msg, String positiveFunctionName, String negativeFunctionName);
复制代码
/** * return boolean 类型返回值: true h5已经处理了返回,native不处理; false h5没有处理返回,native返回上一个非H5页面 */
function gobackIfNeeded(); 复制代码

app的唤醒方式方案:

1.定义scheme: com.xxx.app

2.另外具体页面的打开待定

约定ua: "xxxx XXX/1.3.0", 其中xxxx为系统默认ua。iOS与Android不同。"/"后为app版本号

h5唤起app

h5唤起app已经变成了目前不可或缺的功能之一,做为前端技术栈的必备技术栈之一,咱们须要知道如何在非app环境内唤起app,以及正确识别是系统中是否安装了app.

系统相关

应用名称 URL Scheme
短信 sms://
app store itms-apps://
电话 tel://
无线局域网 App-Prefs:root=WIFI
蓝牙 App-Prefs:root=Bluetooth
蜂窝移动网络 App-Prefs:root=MOBILE_DATA_SETTINGS_ID
我的热点 App-Prefs:root=INTERNET_TETHERING
运营商 App-Prefs:root=Carrier
通知 App-Prefs:root=NOTIFICATIONS_ID
通用 App-Prefs:root=General
通用-关于本机 App-Prefs:root=General&path=About
通用-键盘 App-Prefs:root=General&path=Keyboard
通用-辅助功能 App-Prefs:root=General&path=ACCESSIBILITY
通用-语言与地区 App-Prefs:root=General&path=INTERNATIONAL
通用-还原 App-Prefs:root=Reset
墙纸 App-Prefs:root=Wallpaper
Siri App-Prefs:root=SIRI
隐私 App-Prefs:root=Privacy
Safari App-Prefs:root=SAFARI
音乐 App-Prefs:root=MUSIC
音乐-均衡器 App-Prefs:root=MUSIC&path=com.apple.Music:EQ
照片与相机 App-Prefs:root=Photos
FaceTime App-Prefs:root=FACETIME

应用

应用名称 URL Scheme
微博 weibo://
QQ mqq://
QQ群组 mqqapi://card/show_pslcard?src_type=internal&version=1&card_type=group&uin={QQ群号}
QQ联系人 mqqapi://card/show_pslcard?src_type=internal&version=1&uin={QQ号码}
支付宝 alipay://
微信 weixin://
微信 wechat://
微信-扫一扫 weixin://dl/scan
微信-反馈 weixin://dl/feedback
微信-朋友圈 weixin://dl/moments
微信-设置 weixin://dl/settings
微信-消息通知设置 weixin://dl/notifications
微信-聊天设置 weixin://dl/chat
微信-通用设置 weixin://dl/general
微信-公众号 weixin://dl/officialaccounts
微信-游戏 weixin://dl/games
微信-帮助 weixin://dl/help
微信-我的信息 weixin://dl/profile
微信-功能插件 weixin://dl/features
虾米音乐 xiami://
chrome googlechrome://
微博国际版 weibointernational://
摩拜单车 mobike://
ofo ofoapp://
有道云笔记 youdaonote://
印象笔记 evernote://
今日头条 snssdk141://
网易新闻 newsapp://
网易云音乐 orpheuswidget://
QQ音乐 qqmusic://
QQ音乐最近播放 qqmusic://today?mid=31&k1=2&k4=0
美团外卖 meituanwaimai://
美团 imeituan://
Gmail googlegmail://
网易邮箱 neteasemail://
QQ邮箱 qqmail://
腾讯视频 tenvideo://
爱奇艺 iqiyi://
12306 cn.12306://
有道词典 yddict://
钉钉 dingtalk://

参考文章

相关文章
相关标签/搜索