科伦文档一:

这次是一个最终架构(99.9%就是这样了,后面不会再动底层了),这个架构有这几个要求,在开始之前一定要理解一下意境:

1.不考虑H5页面,全局所有的原生页面共用一个桥。有且仅有一个公共的桥。

2. js是核心数据管理者,js不控制UI的渲染,js只管给数据,具体怎么布局怎么渲染是原生的绝对自由。即:js是主要是请求数据,准备数据,分析数据,并最终传递数据给原生展示,同时响应原生的点击事件处理对应的数据与逻辑,完成缓存与页面跳转等业务逻辑。

3.一个webview对应一个桥。


好了,现在全局所有原生页面只有一个桥,因为一个桥一定对应一个唯一的webview,所有这个原生的桥也有一个webview,也就对应了一个url,这个url在oss云上,不需要打包到本地:

let native_url =  https://static.kelunyy.com/YiYaoKuaPingTai/native/app.html


一、 定义一个BridgeManager类,这个类里面至少有这几个属性:

(1)webview,加载一个指定的url

(2)bridge桥对象

注:这些类非常重要,这个类的一个实例就会对应一个webview,一个url,一个bridge。一定要设计成这样不然后面H5会出问题。后面会发现这个设计相当统一巧妙工整。

class BridgeManager {

    var webview: WKWebview = WKWebview()  //webview

    var url: String = ""

    var bridge: WebviewBridge = WebviewBridge()  //桥

}




二、定义BaseActivity,这是所有页面共同的基类。到目前,我们已经知道他需要有一个name字段,这个name字段是这个页面的名字。在js里面会有对应的js页面和他一一对应,靠的就是这个name。



三、APP一启动,先要加载native_url,这个url里面有所有原生页面的所有代码,他加载成功了,才能进入真正的首页。

(1)App启动,启动后,我做了一个叫RootActivity的页面作为临时的入口显示页面,他只是中间页面用来等待入口webview的加载这个时间的。

RootActivity里面放了一张启动图。从用户视觉来说,感觉app一直卡在启动页面,其实已经到RootActivity了。

(2)在全局放一个webview,因为这个webview是所有原生页面共用的,我觉得放到BaseActivity的静态变量最合适不过了。刚好符合静态变量的定义,所有成员共用的唯一资源。不过我们不应该直接放一个webview,按上面的约定,我们应该放一个BridgeManager的实例。所以是这样(最好和ios设计一致哈,这样我思路统一,方便交流管理):

class BaseActivity {

     static var bridge_manager =  BridgeManager(url: 'https://static.kelunyy.com/YiYaoKuaPingTai/native/app.html') 

      var name: String,

}

现在,我们所有页面都可以访问这个静态的bridge_manager得到对应webview和桥。特别注意,只要加载我提供的h5页面,页面加载完我会回调桥页面加载完成的协议,于是我们的第一个协议来了:(这个之前已经见过了)

appbegin: 表明当前这个web页面加载完成。

不过要注意,之前是一个页面一个桥,现在是所有原生页面共用一个桥,所以这个appbegin,就只会触发一次。触发后,所有原生页面的功能全部可用。此时,需要把app的窗口从RootActivity换成真正的首页。tab页如下:

首页:name=shouye,

分类:fenlei

发现:faxian

购物车:gouwuche

我的:wode


然后,这里有个小注意点,刚好首页是一个复杂页面是H5实现的,你先不考虑首页H5,你把首页想像成原生页面,里面放一个首页两个字先顶替。

另外,其他几个tab页除了我的页面都没给图,你都先直接写个字代表页面,先把tab页切换架构搭建起来。


然后,tab的切换,很明显和逻辑数据无关,之前的旧版本中js控制了的,现在我感觉从数据角度,js完全没必要干涉,而且这个操作原生也很简单,js不需要干涉这种正常原生的普通功能。这时也体现了js的使命与方向。


四、BaseActivity的初步封装,以及验证js是否成功运行生效,获取js传递的数据:

我们要对BaseActivity继续完善封装,这个工具非常重要,因为这个封装在后面非常多的地方调用,好的封装,能统一我们的逻辑,精简代码,先看下ios的代码



class BaseActivity{    

     // action: 是js用来区分这个混编做什么的

     // json_data: 传递给js的数据

     // responseCallback: 回调函数

      fun js(action: String,      json_data: JSON,      responseCallback: BridgeClosure){

         BaseAcitivity.bridge_manager.bridge   .....调用js桥的协议

      }

}


特别注意:

(1)外面调用的action最终是个参数,直接调用js的是同一个handler为“handle”,全部调用js的只有这一个公共的handler,js区分不同请求完全是靠区分action字段。

(2)参数里面不仅包含action信息,还要包含当前页面的name信息。

(3)pid可以忽略,这个项目貌似用不到。


现在到了我们使用刚刚封装的方法的时候了,把当前页面的生命周期传递给js(很明显这个代码应该封装到BaseActivity里面):

当页面加载的时候,调用 js("onLoad")

当页面显示的时候,调用  js("onShow")

当页面隐藏的时候,调用  js("onHide")

当页面销毁的时候,调用  js("onUnload"),


好了,写好这个后,很多js的代码就自动触发了。

下面, 第二个协议:

协议名:log

参数: {content: "要打印的字符串"}

js会调用这个协议,实现在原生IDE里面打印一个字符串content字段。


做了这些之后,在4个tab页,的onLoad和onShow我都做了对应的页面的打印的,如果IDE在切换页面有打印,恭喜,第一步成功啦。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容