作者:此人已死689 | 来源:互联网 | 2023-10-10 22:25
平台化容器API释放接上文:(阅读本文前,建议阅读前三篇文章先)浅谈Hybrid技术的设计与实现浅谈Hybrid技术的设计与实现第二弹浅谈Hybrid技术的设计与实现第三弹——
平台化容器API释放
接上文:(阅读本文前,建议阅读前三篇文章先)
浅谈Hybrid技术的设计与实现
浅谈Hybrid技术的设计与实现第二弹
浅谈Hybrid技术的设计与实现第三弹——落地篇
之前设计Hybrid整块交互的时候,受众都是自己的团队,没有想往“公司化”和“平台化”方向发展,而近期业务的发展逐渐超出预期了,慢慢会有第三方网站接入我们的APP,而且第三方网站还会用一些Native的能力,这个时候之前的使用似乎就不太合适了,所谓JS-SDK就需要存在了。
类似这种需求,做的最完善的当属微信的native容器了,微信这种属于海量容器,对所有的接入方基本一视同仁,就算内部团队会有一些“特权”能力,使用方式与第三方接入都是一套体系,可能只是文档有所不同罢了。微信容器中,最常用的端能力要属:
① 统一登录,获取微信的登录态&使用微信登录,微信方给予第三方应用有限的用户信息(非JS-SDK)
② 分享接口
③ 微信支付
我们今天以微信(中间可能参考其他APP平台)为范本,思考下我们自己的容器如何处理第三方的情况。
我们做这块设计之前,首先需要明确一个定位:
我们的Native容器,应该给第三方网站提供哪些能力?
如果不加限制的提供能力,就属于“内部”项目了,如微信容器一般,对外提供的能力屈指可数,这里是我们一个比较常见的第三方容器:
wx.openApp(appid);
这里的实现方案可以是这样,一般来说,我们对外释放的接口都是比较通用的,像一些私密的接口才会有白名单维护,比如我们自己的app对应的几个图片操作接口:
1 //选取图片接口
2 wx.chooseImage({
3 count: 1, // 默认9
4 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
5 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
6 success: function (res) {
7 var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
8 }
9 });
10 //上传图片接口
11 wx.uploadImage({
12 localId: '', // 需要上传的图片的本地ID,由chooseImage接口获得
13 isShowProgressTips: 1, // 默认为1,显示进度提示
14 success: function (res) {
15 var serverId = res.serverId; // 返回图片的服务器端ID
16 }
17 });
18 //预览图片接口
19 wx.previewImage({
20 current: '', // 当前显示图片的http链接
21 urls: [] // 需要预览的图片http链接列表
22 });
其中预览我把他作为私密接口不予释放,需要特定的appid才能使用,就可以这样:
1 //1代表公共接口,0代表私密接口
2 var apilist = {
3 'chooseImage': 1,
4 'uploadImage': 1,
5 'previewImage': 0
6 };
7 //所有的应用id
8 var appids = [1, 2, 3, 4];
9 //白名单
10 var whitList = [{1: ['previewImage', '其他私密能力']}];
实话实说维护一个appid,这样做的成本比较高,单单做appid和秘钥对于调用者来说也挺麻烦,对于有些比较小的平台来说,可以采取域名白名单的方法,后端维护一个列表:
1 //域名白名单
2 var whitList = [
3 {'domain.com': ['previewImage', '其他私密能力']},
4 {'domain2.com': ['previewImage', 'uploadImage', '其他私密能力']}
5 ];
这种方法比较做起来成本较低,一些小一点的平台可以这样做,而这样做的话,需要考虑每个域名对应的App打开协议,可能会有打开需求,我们这里采用的比较简单的方案,域名白名单,表设计大概这样:
1 var whitList = [
2 {id: 'domain.com', apis: ['previewImage', '其他私密能力'], schema: 'xxxx://'},
3 {id: 'domain2.com', apis: ['previewImage', 'uploadImage', '其他私密能力'], schema: 'xxxx://'}
4 ];
我们明确知道某个域名具有哪些能力,如果不具有这些能力就不予理睬,我们也知道某个域名具有打开某个app的权限。
能力列表
明确了能力,以及能力限制,接下来我们便来整理一下几个核心的对外接口。
header的定义
我们这里做的第一件事情,依旧是header的定义,并且对于第三方,我们要求header只能是这个样子:
针对header我们有以下约定:
① 进入一个页面默认包含,返回+title+功能菜单三个按钮
② 返回按钮默认执行history.back()的操作,如果history.length为1,则退到native上一步操作
③ title默认读取html中的title标签,可使用接口更改
④ 关闭按钮默认不存在,在history比较深并且点击过一次返回按钮后展示出来,防止页面死循环假死
⑤ 功能菜单默认弹出以下菜单项,其中分享文案默认读取当前tdk(title+description)标签,和第一张图片,也可读取页面标签定制(也可以使用接口定制,事实上容器不会做这种业务工作,是业务框架层bridge做的工作),比如:
1 <meta name="med-title" content="分享标题">
2 <meta name="med-description" content="分享内容">
3 <meta name="med-link" content="http://....">
4 <meta name="med-img" content="http://....">
我们业务层代码,或者bridge代码会将之翻译为:
1 wx.onMenuShareTimeline({
2 title: medTitle,
3 link: medLink,
4 imgUrl: medImg,
5 trigger: function (res) {
6 },
7 success: function (res) {
8 },
9 cancel: function (res) {
10 },
11 fail: function (res) {
12 }
13 });
分享到朋友圈&QQ空间
分享到朋友圈前端代码为:
1 MED.origin = MED.origin || {};
2 //shareTimeline分享到朋友圈;shareAppMessage分享给朋友;shareQQ分享给qq好友;shareQZone分享到空间,设置方面稍作更改即可
3 MED.origin.medShareXXX = MED.medShareXXX = function (o) {
4 _.requestHybrid({
5 tagname: 'shareTimeline',
6 param: {
7 title: o.title,
8 desc: o.desc,
9 image: o.img,
10 url: o.link
11 },
12 callback: function(data) {
13 if(data.code === 0) {
14 o.success && o.success(data.data);
15 } else {
16 o.cancel && o.cancel(data.data);
17 }
18 }
19 });
20 };
H5上传图片方面的体验很差,这块我们在H5情况下依旧使用file上传,但是在容器里面释放几个图片操作接口
图片操作
1 //选取图片,最初想把选取和上传合并的,后面想想还是分开合适
2 _.requestHybrid({
3 tagname: 'chooseImage',
4 param: {
5 //1-9张限制
6 count: 1,
7 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
8 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
9 },
10 callback: function(data) {
11 if(data.code === 0) {
12 //这块有一些疑问,选择和上传还是连着一起算了
13 o.success && o.success(data.data.localIds); // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片;
14 } else {
15 o.error && o.error(data.data);
16 }
17 }
18 });
19
20 //上传图片
21 _.requestHybrid({
22 tagname: 'uploadImage',
23 param: {
24 //由chooseImage获取
25 localId: 1,
26 isShowProgressTips: 1 // 默认为1,显示进度提示
27 },
28 callback: function(data) {
29 if(data.code === 0) {
30 o.success && o.success(data.data.url); // 返回src;
31 } else {
32 o.error && o.error(data.data);
33 }
34 }
35 });
36
37 //图片预览,预览的地方做个图片下载的功能
38 _.requestHybrid({
39 tagname: 'previewImage',
40 param: {
41 current: '', // 当前显示图片的http链接
42 urls: [] // 需要预览的图片http链接列表
43 }
44 });
获取网络状态
1 //获取网络状态
2 _.requestHybrid({
3 tagname: 'getNetworkType',
4 callback: function(data) {
5 //data.networkType 2g 3g 4g wifi
6 }
7 });
地图操作
Native的地理操作一块相对H5体验要好一些,特别是地图展示一块的体验要好得多,所以这两块也需要释放API:
1 //获取经纬度信息
2 _.requestHybrid({
3 tagname: 'getLocation',
4 callback: function(data) {
5 if(data.code !== 0) return;
6 var res = data.res;
7 var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
8 var lOngitude= res.longitude; // 经度,浮点数,范围为180 ~ -180。
9 var speed = res.speed; // 速度,以米/每秒计
10 var accuracy = res.accuracy; // 位置精度
11 }
12 });
13
14 //根据经纬度等信息打开native地图
15 _.requestHybrid({
16 tagname: 'openLocation',
17 params: {
18 latitude: 0, // 纬度,浮点数,范围为90 ~ -90
19 longitude: 0, // 经度,浮点数,范围为180 ~ -180。
20 name: '', // 位置名
21 address: '', // 地址详情说明
22 scale: 1, // 地图缩放级别,整形值,范围从1~28。默认为最大
23 infoUrl: '' // 在查看位置界面底部显示的超链接,可点击跳转
24 }
25 });
所谓的name和地址是指下面信息框这一坨:
界面操作
关闭当前webview,回到native上一次操作:
1 _.requestHybrid({
2 tagname: 'closeWindow'
3 });
native键盘
H5在文字输入一块可以说是弱爆了,比Native体验差远了,所以我们在native键盘这块也做了一个nativeUI,如果需求允许可以使用:
1 //唤起输入文字的软键盘
2 //这块代码有一些业务耦合,需要如何处理下????
3 _.requestHybrid({
4 tagname: 'showKeyboard',
5 param: {
6 hasImg: 1, //是否需要上传图片区域,如果需要则为1,不需要为0
7 count: 1, //如果需要图片上传,这里限制图片选择的数量,1-9
8 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
9 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
10 textMin: 20, //文字要求最少输入字符数
11 textMax: 500 //文字要求最多输入字符数
12 },
13 //输入结束的回调或者说点击发送时候的回调
14 callback: function (data) {
15 var cOntent= data.content;//文字内容
16 var urls = data.urls;//图片地址
17 }
18 });
结语
今天分析了一下第三方webview需要释放的接口,接下来我这边开始落地,我们真实工作中可能还要考虑新老容器过渡等问题,本文含金量相对较小,各位谨慎阅读吧。