深入凡泰小程序之一: 小程序原理及模拟

本文将介绍小程序的核心视图层逻辑层分离架构,并通过iOS的代码来模拟这种双线程模型。

什么是小程序

小程序是一种新的移动应用程序格式,是一种依赖Web技术,但也集成了原生应用程序功能的混合解决方案。

目前市面上小程序平台微信、支付宝、百度、头条、京东、凡泰 等;小程序一些特性有助于填补Web和原生平台之间的鸿沟,因此小程序受到了一些超级应用程序的欢迎。

- 它不需要安装,支持热更新。

- 具备多个Web视图以提高性能。

- 它提供了一些通过原生路径访问操作系统功能(原生接口)或数据的机制。

- 它的内容通常更值得信赖,因为应用程序需要由平台验证。

小程序可以分发到多个小程序平台(Web、原生应用,甚至是OS)。这些平台还为小程序提供了入口,帮助用户轻松找到所需的应用。

小程序核心功能

分离视图层与逻辑层

在小程序中,视图层通常与逻辑层分离。

视图层View负责渲染小程序页面,包括Web组件和原生组件渲染,可以将其视为混合渲染。例如,Web组件渲染可以由WebView处理,但WebView不支持某些Web组件渲染,或者是性能受限;小程序还依赖于某些原生组件,例如地图、视频等。

逻辑层Service是用主要用于执行小程序的JS逻辑。主要负责小程序的事件处理、API调用和生命周期管理。扩展的原生功能通常来自宿主原生应用程序或操作系统,这些功能包括拍照、位置、蓝牙、网络状态、文件处理、扫描、电话等。它们通过某些API调用。当小程序调用原生API时,它会将API调用传递给扩展的原生功能,以便通过JSBridge进一步处理,并通过JSBridge从扩展的原生功能获取结果。Service为每个Render建立连接,传输需要渲染的数据以进一步处理。

如果事件由小程序页面中的组件触发,则此页面将向Service发送事件以进一步处理。同时,页面将等待Service发送的数据来重新渲染小程序页面。

渲染过程可被视为无状态,并且所有状态都将存储在Service中。

视图层和逻辑层分离有很多好处:

方便多个小程序页面之间的数据共享和交互。

在小程序的生命周期中具有相同的上下文可以为具备原生应用程序开发背景的开发人员提供熟悉的编码体验。

Service和View的分离和并行实现可以防止JS执行影响或减慢页面渲染,这有助于提高渲染性能。

因为JS在Service层执行,所以JS里面操作的DOM将不会对View层产生影响,所以小程序是不能操作DOM结构的,这也就使得小程序的性能比传统的H5更好。

小程序双线程模型模拟

接下来我们将用iOS代码来模拟上述的双线程模型。首先我们来实现视图层与逻辑层的数据通讯

如上图所示,视图层与逻辑层都分别通过JS Bridge的publish和subscribe来实现数据的收发。

// 首先订阅数据回调

JSBridge.subscribe('PAGE_EVENT', function (params) {

 // ... 这里对返回的数据进行处理

})

// 向JS Bridge发布数据

// eventName: 用于标识事件名

// data: 为传递的数据

JSBridge.publish('PAGE_EVENT', {eventName: 'onTest',data: {}})

首先需要对WKWebView初始化,

WKUserContentController *userContentController = [WKUserContentController new];

NSString *souce = @"window.__fcjs_environment='miniprogram'";

WKUserScript *script = [[WKUserScript alloc] initWithSource:souce injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:true];

[userContentController addUserScript:script];

[userContentController addScriptMessageHandler:self name:@"publishHandler"];


WKWebViewConfiguration *wkWebViewConfiguration = [WKWebViewConfiguration new];

wkWebViewConfiguration.allowsInlineMediaPlayback = YES;

wkWebViewConfiguration.userContentController = userContentController;


if (@available(iOS 9.0, *)) {

    [wkWebViewConfiguration.preferences setValue:@(true) forKey:@"allowFileAccessFromFileURLs"];

}

WKPreferences *preferences = [WKPreferences new];

preferences.javaScriptCanOpenWindowsAutomatically = YES;

wkWebViewConfiguration.preferences = preferences;


self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:wkWebViewConfiguration];

self.webView.clipsToBounds = YES;

self.webView.allowsBackForwardNavigationGestures = YES;

[self.view addSubview:self.webView];

NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"view.html" ofType:nil];

NSURL *fileURL = [NSURL fileURLWithPath:urlStr];

[self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL];

WKWebView事件回调处理

// 执行视图层事件回调

- (void)callSubscribeHandlerWithEvent:(NSString *)eventName param:(NSString *)jsonParam

{

    NSString *js = [NSString stringWithFormat:@"FinChatJSBridge.subscribeHandler('%@',%@)",eventName,jsonParam];

    [self evaluateJavaScript:js completionHandler:nil];



}


- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void(^)(id result,NSError *error))completionHandler

{


    [self.webView evaluateJavaScript:javaScriptString completionHandler:completionHandler];

}


#pragma mark - WKScriptMessageHandler

// 视图层JSBridge请求接收处理

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message

{

    if ([message.name isEqualToString:@"publishHandler"]) {

        NSString *e = message.body[@"event"];

        [self.service callSubscribeHandlerWithEvent:e param:message.body[@"paramsString"]];

    }

}

视图层代码

function onTest() {

    console.log('aaa')

    FinChatJSBridge.subscribe('PAGE_EVENT', function (params) {

                              document.getElementById('testId').innerHTML = params.data.title                                })

    FinChatJSBridge.publish('PAGE_EVENT', {

      eventName: 'onTest',data: {}

    })

}

<div id="testId">我来自视图层!</div><input type="button" value="调用JS逻辑层setData" style="border-radius:15px;background:#ed0c50;border: #EDD70C;color: white;font-size: 14px; width: 80%;" onclick="onTest();" />

逻辑层代码

  // page 对像模拟

 var Page = {

        setData: function(data) {

             ServiceJSBridge.publish('PAGE_EVENT', {

                   eventName: 'onPageDataChange',data:data

                 })

        },

        methods: {

            onTest: function() {

                Page.setData({

                             title: '我来自JS代码更新'

                             })

                console.log('my on Test')

            }

        }

    }

var onWebviewEvent = function (fn) {

  ServiceJSBridge.subscribe('PAGE_EVENT', function (params) {

    var data = params.data,eventName = params.eventName;

  fn({

      data: data,

      eventName: eventName

    })

  })

}

var doWebviewEvent = function ( pEvent, params) { // do dom ready

  if (Page.methods.hasOwnProperty(pEvent)) {

      Page.methods[pEvent].call(params);

  }

}

onWebviewEvent(function (params) {

  var eventName = params.eventName

  var data = params.data

  return doWebviewEvent( eventName, data)

})

具体代码请参考(https://github.com/finochat/myapplet)

其他说明:

凡泰极客希望把迄今为止只有互联网巨头们才拥有的小程序技术能力,以“白牌”(white label)方式赋能给传统企业。

我们把“小程序运行时”实现成一个可私有化部署的iOS和Android版本的SDK,任何机构的App均可以嵌入该组件而瞬间获得运行小程序的能力;同时也提供了“小程序开放平台”的解决方案,供任何机构、行业组织运行自己的小程序生态、统一上下架管理自己以及合作伙伴们的业务场景。

与互联网巨头方案不一样的是,我们的方案不仅更加开放(提供API接口,支持二次开发),也更聚焦行业在合规监管方面的特殊行业诉求。目前已在多家银行、保险、证券以及相关行业机构落地,并能够自有机房内独立部署运行。不仅如此,“凡泰小程序技术”语法结构和微信小程序兼容,一次开发,多处上架,可降低开发成本,提升研发效率。

凡泰小程序当前已经开放了一键部署功能,现可免费体验,只需5行代码30分钟,即可在您的应用内集成「小程序运行时」,点击https://mp.finogeeks.com/#/experience进入官网通过手机号即可完成注册体验

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容