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

本文將介紹小程序的核心視圖層邏輯層分離架構(gòu),并通過iOS的代碼來模擬這種雙線程模型。

什么是小程序

小程序是一種新的移動應(yīng)用程序格式,是一種依賴Web技術(shù),但也集成了原生應(yīng)用程序功能的混合解決方案。

目前市面上小程序平臺微信、支付寶、百度、頭條、京東、凡泰 等;小程序一些特性有助于填補Web和原生平臺之間的鴻溝,因此小程序受到了一些超級應(yīng)用程序的歡迎。

- 它不需要安裝,支持熱更新。

- 具備多個Web視圖以提高性能。

- 它提供了一些通過原生路徑訪問操作系統(tǒng)功能(原生接口)或數(shù)據(jù)的機制。

- 它的內(nèi)容通常更值得信賴,因為應(yīng)用程序需要由平臺驗證。

小程序可以分發(fā)到多個小程序平臺(Web、原生應(yīng)用,甚至是OS)。這些平臺還為小程序提供了入口,幫助用戶輕松找到所需的應(yīng)用。

小程序核心功能

分離視圖層與邏輯層

在小程序中,視圖層通常與邏輯層分離。

視圖層View負責(zé)渲染小程序頁面,包括Web組件和原生組件渲染,可以將其視為混合渲染。例如,Web組件渲染可以由WebView處理,但WebView不支持某些Web組件渲染,或者是性能受限;小程序還依賴于某些原生組件,例如地圖、視頻等。

邏輯層Service是用主要用于執(zhí)行小程序的JS邏輯。主要負責(zé)小程序的事件處理、API調(diào)用和生命周期管理。擴展的原生功能通常來自宿主原生應(yīng)用程序或操作系統(tǒng),這些功能包括拍照、位置、藍牙、網(wǎng)絡(luò)狀態(tài)、文件處理、掃描、電話等。它們通過某些API調(diào)用。當小程序調(diào)用原生API時,它會將API調(diào)用傳遞給擴展的原生功能,以便通過JSBridge進一步處理,并通過JSBridge從擴展的原生功能獲取結(jié)果。Service為每個Render建立連接,傳輸需要渲染的數(shù)據(jù)以進一步處理。

如果事件由小程序頁面中的組件觸發(fā),則此頁面將向Service發(fā)送事件以進一步處理。同時,頁面將等待Service發(fā)送的數(shù)據(jù)來重新渲染小程序頁面。

渲染過程可被視為無狀態(tài),并且所有狀態(tài)都將存儲在Service中。

視圖層和邏輯層分離有很多好處:

方便多個小程序頁面之間的數(shù)據(jù)共享和交互。

在小程序的生命周期中具有相同的上下文可以為具備原生應(yīng)用程序開發(fā)背景的開發(fā)人員提供熟悉的編碼體驗。

Service和View的分離和并行實現(xiàn)可以防止JS執(zhí)行影響或減慢頁面渲染,這有助于提高渲染性能。

因為JS在Service層執(zhí)行,所以JS里面操作的DOM將不會對View層產(chǎn)生影響,所以小程序是不能操作DOM結(jié)構(gòu)的,這也就使得小程序的性能比傳統(tǒng)的H5更好。

小程序雙線程模型模擬

接下來我們將用iOS代碼來模擬上述的雙線程模型。首先我們來實現(xiàn)視圖層與邏輯層的數(shù)據(jù)通訊

如上圖所示,視圖層與邏輯層都分別通過JS Bridge的publish和subscribe來實現(xiàn)數(shù)據(jù)的收發(fā)。

// 首先訂閱數(shù)據(jù)回調(diào)

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

?// ... 這里對返回的數(shù)據(jù)進行處理

})

// 向JS Bridge發(fā)布數(shù)據(jù)

// eventName: 用于標識事件名

// data: 為傳遞的數(shù)據(jù)

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事件回調(diào)處理

// 執(zhí)行視圖層事件回調(diào)

- (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="調(diào)用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)

其他說明:

凡泰極客希望把迄今為止只有互聯(lián)網(wǎng)巨頭們才擁有的小程序技術(shù)能力,以“白牌”(white label)方式賦能給傳統(tǒng)企業(yè)。

我們把“小程序運行時”實現(xiàn)成一個可私有化部署的iOS和Android版本的SDK,任何機構(gòu)的App均可以嵌入該組件而瞬間獲得運行小程序的能力;同時也提供了“小程序開放平臺”的解決方案,供任何機構(gòu)、行業(yè)組織運行自己的小程序生態(tài)、統(tǒng)一上下架管理自己以及合作伙伴們的業(yè)務(wù)場景。

與互聯(lián)網(wǎng)巨頭方案不一樣的是,我們的方案不僅更加開放(提供API接口,支持二次開發(fā)),也更聚焦行業(yè)在合規(guī)監(jiān)管方面的特殊行業(yè)訴求。目前已在多家銀行、保險、證券以及相關(guān)行業(yè)機構(gòu)落地,并能夠自有機房內(nèi)獨立部署運行。不僅如此,“凡泰小程序技術(shù)”語法結(jié)構(gòu)和微信小程序兼容,一次開發(fā),多處上架,可降低開發(fā)成本,提升研發(fā)效率。

凡泰小程序當前已經(jīng)開放了一鍵部署功能,現(xiàn)可免費體驗,只需5行代碼30分鐘,即可在您的應(yīng)用內(nèi)集成「小程序運行時」,點擊https://mp.finogeeks.com/#/experience進入官網(wǎng)通過手機號即可完成注冊體驗

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容