虚拟货币rpx是什么币
微信发布小程序平台后,国内各大APP火速跟进,纷纷发布了自己的小程序平台。
速度真的很快,难道被微信形容“拥有出色体验”的小程序平台很容易实现?我们可以再造一个吗?
起初,作者甚至不知道小程序是由Native实现,还是网页实现。既然要再造一个,那么首先要做的就是来了解小程序平台实现原理。
调研
没有参与过小程序平台的建设,所以只能发动搜索技能。所以这篇文章也更多的是管中窥豹,抛砖引玉。
搜索多篇与小程序实现原理有关的文章,认真拜读,发现在微信小程序平台发布之初,微信团队将小程序构建相关的脚本直接下发给了微信开发者工具,也就是小程序构建是在开发者端。现在新版的微信开发者工具中已经没有相关脚本了,推测是将构建转移到了服务器端。
从相关的文章中,我们了解猜想到了微信小程序实现方式:UI层由网页+原生渲染(部分组件是原生实现),Native运行逻辑层。
技术方案
UI层渲染采用webview,js逻辑层呢?
React Native的js引擎主要采用了JavaScriptCore(苹果Safari浏览器js引擎),Weex则是采用了Chrome V8引擎。
实现
道理你都懂,那怎么实现呢?
UI和js逻辑
在实现之前,我们首先来看看微信小程序的代码,分析一下。以一个小程序的index页面为例,其代码包含文件:index.js、index.json、index.wxml、index.wxss
index.js
index.js主要是业务逻辑代码,内容大致为:
小程序的页面逻辑代码均包含在Page({...})中。在js中,Page是一个函数。所以,小程序应该是调用了Native或者js的Page函数。
小编倾向于Page是调用了js函数。因为如果是Native函数,那么js中的this关键字将需要Native进行处理,js引擎可以处理的内容,没有必要交给Native来进行处理,或者是小编不知道Native有比较好的处理方式。
所以,我们需要处理的第一个内容是:使用js定义Page函数或者class,两者均可以实现。
index.wxml
index.wxml是UI,是微信自定义xml标签,例如:
<!--index.wxml--><view class="container"> <view class="userinfo"> <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button> <block wx:else> <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image> <text class="userinfo-nickname">{{userInfo.nickName}}</text> </block> </view> <view class="usermotto"> <text class="user-motto">{{motto}}</text> </view></view>
自定义一整套的xml标签、属性会比较耗费时间,我们可以直接使用html标签。
index.wxss
index.wxss主要是样式,和css基本一样,其内容我们完全可以直接引入网页中。
微信小程序则是统一了rpx单位,想必是为了更好的兼容不同屏幕大小。
index.json
这个文件则是该页面的一些基本配置。我们主要关心一下usingComponents
{ "usingComponents": {}}
这个应该就是小程序可以实现组件化开发的原因。usingComponents直接告诉了Native页面使用了哪些组件,方便Native获取组件模板和逻辑,然后进行渲染。
定义Page
我们来使用js定义一个Page class,来作为每个页面的实例。当然也可以使用函数实现。
class Page { constructor(config) { this.data = config.data JSBridge.setData(config.data) // 小程序的onLoad生命周期函数 this.onLoad = config.onLoad // 这里与小程序有点不一样 // 模仿vue将非生命周期的函数都赋给methods属性 if (config.methods) { // 将所有method都指给class for (let key in config.methods) { this.key = config.methods[key] } } }}
另外我们需要注意的是小程序的setData函数。setData函数应该是调用Native,通知Native数据变更,重新渲染UI,所以我们还要在该class实现setData函数
// page.jsclass Page { constructor(config) { this.data = config.data JSBridge.setData(config.data) // 小程序的onLoad生命周期函数 this.onLoad = config.onLoad // 这里与小程序有点不一样 // 模仿vue将非生命周期的函数都赋给methods属性 if (config.methods) { // 将所有method都指给class for (let key in config.methods) { this.key = config.methods[key] } } } setData (data) { // JSBridge提供Native与js互相调用的api JSBridge.setData(data) }}
定义模板
我们应该定义一个html模板,用来在webview中渲染UI。
<!-- templage.html --><!DOCTYPE html><html><head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>hybrid</title> <meta name="viewport" content="width=device-width, initial-scale=1"></head><body> <!-- app dom下渲染UI --> <div id="app">{{template}}</div></body></html>
这里涉及到一个比较重要的问题:UI的更新。
考虑到性能,实现差量更新比较好。小编因此也再看了一遍Vue的虚拟DOM实现,其中涉及到差量更新。
但是为了快速实现原型,我们直接进行全局更新。如何进行更新,这里采用native调用webview中js方法来实现。
// templage.js// 可以inlinevar preTree = null/*** 渲染UI* @param {Object} domTree 树结构*/window.render = function (domTree) { if (!domTree) return // init UI document.querySelector('#app')[xss_clean] = domTree}12// javathis.webView.loadUrl("_javascript:render('" + newTemplate + "')");
至此,我们就可以作手来实现业务代码了。
业务代码
实现模板index.xml和index.js逻辑,css暂不实现。
index.xml
<div> <div onclick=onText">{{text}}</div></div>
index.js
var page = new Page({ data: { text: 'Hi, Java' }, onLoad: function () { this.setData({ text: 'I am Javascript' }) }, methods: { onText: function () { this.setData({ text: 'Hi, Javascript' }) } }})
Native端
通过实现上文的UI和js逻辑我们需要Native端实现JSBridge api。
我们首先要解决的是js引擎的使用。本文以Android为例,选取Chrome V8作为js引擎。
J2V8
J2V8使用Java封装了对Chrome V8的操作,跨平台开发Tabris正是使用了J2V8来实现js构建原生应用。
我们可以通过官网 了解如何使用J2V8。
Android引入
使用Android Studio新建APP后,在build.gradle文件中添加J2V8依赖,选取aar版(已编译)或者使用J2V8源码自行编译:
dependencies { implementation 'com.eclipsesource.j2v8:j2v8:4.8.2@aar'}
实现JSBridge
定义一个Java类JSBridge,该类至少包含setData接口
Native初始化渲染
Android中我们首先获取template.html内容,话不多说,看下面的Android代码注释。
总结
这是啥啊?这不是再造一个浏览器吗?!
不不,浏览器远比这复杂,并且js不能直接操作dom(也可以定义接口来实现),还有很多内容需要完善,例如实现js的window函数:setTimeout等。
至于性能方面,是不是比直接使用webview的性能要好,这还要进一步完善丰富原型和DEMO。