LuaView初識

前言

作為一名iOS開發(fā)工程師辛友,App的動態(tài)化是一種趨勢速侈,畢竟需求的增多率寡,頻繁的提交版本、更新版本對用戶體驗上肯定會有影響倚搬。當(dāng)然動態(tài)化的方案有很多種:RN冶共,Weex,LuaView等。對于一個對H5捅僵、React 零基礎(chǔ)的小白家卖,我準(zhǔn)備還是從LuaView入手。最后還想說一句庙楚,沒想到在簡書寫的第一篇文章是關(guān)于LuaView的上荡。好吧,我承認(rèn)我比較懶馒闷!

什么是LuaView酪捡?

LuaView是一種運行在一個ViewController/Activity中,可以靈活加載Lua腳本纳账,并能夠按照Native的方式運行的一種面向業(yè)務(wù)的開發(fā)技術(shù)方案逛薇。

LuaViewSDK使用lua虛擬機進行腳本解析,通過構(gòu)建lua與native之間的一系列基礎(chǔ)bridge功能疏虫,從另一個角度實現(xiàn)了動態(tài)化的native能力永罚。

而對于為何選用Lua,其最大的優(yōu)勢就是:lua語法精煉直觀议薪,lua虛擬機輕量高效尤蛮,使用Native編程模式,Native開發(fā)人員容易上手斯议。

以上很不要臉的取自其官方文檔的描述:?https://alibaba.github.io/LuaViewSDK/guide.html

LuaViewSDK 是阿里開源的一個實現(xiàn)動態(tài)化方案的框架产捞。開源地址:?https://github.com/alibaba/LuaViewSDK

目前其SDK由阿里的一個團隊來維護。個人感覺推廣力沒有Weex高哼御。官方文檔也很久沒有更新了坯临。不過提供了一個官方技術(shù)交流群:539262083 。

LuaViewSDK的整體架構(gòu)

上圖是LuaViewSDK的架構(gòu):(由下往上)

Native? & Framework :表示了Android恋昼、iOS及其對應(yīng)的框架層看靠。

Lua Engine:即Lua虛擬機,Android對應(yīng)LuaJ液肌,iOS對應(yīng)LuaC挟炬。作為lua腳本和nati語言之間的橋梁,將lua腳本翻譯成native能夠識別的目標(biāo)語言嗦哆。

Lua-Native UI Lib:LuaView的核心組件谤祖。其實LuaView對Native的各種UI組件進行了再次封裝,并且注冊到了Lua環(huán)境中老速,Lua腳本可以直接創(chuàng)建和操作這些組件粥喜,來達到創(chuàng)建和控制Native組件。(其實查看SDK源碼橘券,會發(fā)現(xiàn)额湘,不僅封裝了UI組件卿吐,還有一些方法類,如Timer锋华,Gesture等)嗡官。

Script Manager:Lua腳本管理器,用于腳本的解壓供置、驗證谨湘、加解密、解壓縮等工作芥丧。

Security:Lua腳本的校驗工作(完整性和安全性的校驗)。

Lua Script & Lua UI Lib:Lua 業(yè)務(wù)腳本以及 Lua 層的 UI 庫坊罢。

LuaView的基本用法

LuaView

第一種方式续担,直接創(chuàng)建LuaView對象,添加到你想渲染的View上活孩,運行腳本進行界面渲染物遇。

//1、創(chuàng)建LuaView憾儒,LView為LuaView子類(SDK封裝的)

self.lv= [[LView alloc]initWithFrame:lvRect];

self.lv.viewController= self;

[self.view addSubview:self.lv];

//2. 加載并運行腳本

[self.lv runFile:scriptFileName];

....

//3询兴、LuaView對象被回收之前必須清理內(nèi)存

[luaview releaseLuaView];

第二種方式,創(chuàng)建LViewController的控制器對象起趾,其屬性 lv 就是一個LuaView 對象诗舰,故運行腳本一樣實現(xiàn)了界面渲染。其已經(jīng)做好了各種生命周期和內(nèi)存管理的處理训裆,所以不用主動去釋放眶根。

//1. 創(chuàng)建LuaView VC

LViewController*luaVC=[[LViewController alloc]init];

//2. 加載并運行腳本

[luaVC.lv runFile:scriptFileName];

此處遇到一坑:

由于我初次使用lua,對其語法不熟边琉,自己創(chuàng)建demo運行腳本時属百,用了別人寫的一個簡單demo的腳本:繪制一個label”湟蹋可是運行后族扰,發(fā)現(xiàn)沒報錯,但是也沒繪制定欧,界面白板渔呵,也沒用返回錯誤提示。百思不得其解忧额!最后對比了下別人 demo 和我的 demo 的 LuaViewSDK厘肮,發(fā)現(xiàn)版本不一致,別人的是 2.5.xx.x睦番,而我的版本是0.5.1(最新的)类茂。而原先 LuaViewSDK 語法和 lua 標(biāo)準(zhǔn)語法有區(qū)別 :‘.’ 和 ':' 互換了耍属。最新SDK支持的lua標(biāo)準(zhǔn)語法(冒號調(diào)用方法,點調(diào)用屬性)巩检,所以我用最新SDK 運行原來語法寫成的腳本厚骗,是有問題的,語法不一致兢哭。最新的SDK中领舰,LuaView 的子類 LView 有一屬性 changeGrammar(默認(rèn)為NO),設(shè)置為YES會進行語法轉(zhuǎn)換迟螺。若新SDK 運行老語法的lua腳本冲秽,則需要將此屬性設(shè)置為 YES 。

而由于我項目中既有自己使用lua標(biāo)準(zhǔn)語法寫的腳本矩父,也有從別人demo拷貝過來的老語法lua腳本锉桑。故我想當(dāng)然的講 changeGrammar 設(shè)置為 YES,結(jié)果發(fā)現(xiàn)老語法lua腳本正常渲染界面窍株,標(biāo)準(zhǔn)語法腳本卻渲染失敗民轴,沒有錯誤提示,白板球订。后來發(fā)現(xiàn) changeGrammar 設(shè)置為YES后裸,并非將lua語法轉(zhuǎn)換成標(biāo)準(zhǔn)語法,而是遍歷腳本后冒滩,將 ‘.’ 和 ':' 進行互換微驶,所以標(biāo)準(zhǔn)語法寫的lua腳本又被轉(zhuǎn)換了。

所以標(biāo)準(zhǔn)語法的lua腳本旦部,changeGrammar 千萬別設(shè)置為 YES祈搜。

LuaViewCore

LuaViewCore其實就是Lua的虛擬機,負責(zé)實現(xiàn)了Lua腳本到Native語言的映射士八。查看LuaView.h/m源碼容燕,會發(fā)現(xiàn)LuaView初始化時,會創(chuàng)建一個?LuaViewCore 的對象婚度,即一個?LuaView?對應(yīng)一個 LuaViewCore蘸秘。

當(dāng)業(yè)務(wù)需要要求一個頁面有多個子View都需要lua控制渲染時,若通過創(chuàng)建多個LuaView方式來渲染蝗茁,則會創(chuàng)建多個LuaViewCore醋虏,這樣或多或少會影響性能。那么如何實現(xiàn)共享一個Lua虛擬機哮翘,即共享LuaViewCore颈嚼,來渲染多個界面。

//1饭寺、初始化LuaViewCore

self.lvCore = [[LuaViewCore alloc]init];

//2阻课、運行腳本

[self.lvCore runFile:@”luaName.lua”];

//? ? [self.lvCore loadFile:@”luaName.lua”];

//3叫挟、調(diào)用腳本里的方法 topViewUI/bottomViewUI ,在指定的 self.topView/self.bottomView 進行UI渲染

//str:成功則返回nil限煞,失敗則返回失敗原因

NSString *str0 = [self.lvCore callLua:@"topViewUI" environment:self.topView args:nil];

NSLog(@"%@",str0?str0:@"topViewUI-sucessed");

NSString *str1 = [self.lvCore callLua:@"bottomViewUI" environment:self.bottomView args:nil];

NSLog(@"%@",str1?str1:@"bottomViewUI-sucessed");

對應(yīng)的腳本 luaName.lua 如下:

function topViewUI( )

aLabel = Label();

aLabel:text("aaaa");

aLabel:frame(0, 0, 100, 30);

end

function bottomViewUI()

aLabel = Label();

aLabel:text("cccc");

aLabel:frame(0, 0, 100, 30);

end

此處遇到一坑:

正如我前面所述抹恳,其官方文檔很久沒有更新,可能維護也很少署驻。其官方描述?LuaViewCore 用法是這樣的:LuaViewCore初始化后奋献,load 腳本,然后就可以調(diào)用腳本的方法旺上。但是按照這個流程瓶蚂,調(diào)用腳本方法,會返回錯誤信息“function is nil error”抚官,即方法找不到扬跋。原因是,在lua中凌节,方法的定義是放在腳本運行時的,而非編譯時洒试。故僅僅編譯腳本倍奢,是無法調(diào)用腳本方法的。正確的流程是:LuaViewCore初始化后垒棋,run 腳本卒煞,然后就可以調(diào)用腳本的方法。(此處已和其官方團隊聯(lián)系確認(rèn)叼架,是其文檔有誤)

Native自定義功能橋接

源碼解析

在實現(xiàn)自定義功能橋接到Lua層之前畔裕,首先要從源碼入手,了解LuaView是如何封裝Native控件乖订,并且注冊到Lua環(huán)境中扮饶,Lua腳本可以任意創(chuàng)建和操作的!

正如上面所言乍构,LuaView 初始化時甜无,會初始化一個 LuaViewCore,然后就沒有其他什么特別的代碼哥遮。LuaViewCore 對象作為Lua虛擬機岂丘,所以密碼就在他這里。LuaViewCore 的初始化方法如下:

myInit 方法實現(xiàn)了屬性的初值賦值等眠饮。關(guān)鍵在于 registeLibs 方法奥帘。

此方法將所有LuaViewSDK封裝的NativeUI進行了遍歷注冊到Lua環(huán)境中。

而LVClassProtocal 協(xié)議的 +(int) lvClassDefine:(lua_State *)L globalName:(NSString*) globalName 方法仪召,即每個封裝的UI類需要實現(xiàn)的寨蹋,完成類及其方法注冊到Lua環(huán)境松蒜。比如LVImage:

lua是一種嵌入式的語言,可以作為c的擴展钥庇,也可以用c來編寫模塊了擴展lua牍鞠。而在進行數(shù)據(jù)交互的時候,存在這這么一個棧评姨,這個棧的作用是存儲lua和c交互的參數(shù)难述,返回值等。如lua調(diào)用c函數(shù)并傳入?yún)?shù)吐句,所有參數(shù)會先壓入這個棧胁后,c函數(shù)執(zhí)行時從棧中獲取參數(shù),執(zhí)行完后嗦枢,也會把返回值壓入此棧攀芯,lua從此棧中獲取返回值。(我個人理解是這樣的文虏,如有誤侣诺,煩請指出)

所以,上面LVImage的注冊氧秘,首先是將類名和其初始化方法壓棧年鸳,通過 lua_setglobal 方法,將棧頂?shù)念惷秃瘮?shù)注冊到lua環(huán)境中丸相,并通過globalName(此處是 "Image")進行標(biāo)注搔确。如此lua腳本中就可以通過 Image() 來創(chuàng)建LVImage對象。

而下面的 luaL_Reg 結(jié)構(gòu)體灭忠,則包含了一組 keyStr -- 方法膳算。則是將這組函數(shù)注冊到Lua環(huán)境中,作為全局函數(shù)弛作。Lua腳本中LVImage對象就可以調(diào)用這些方法涕蜂。

以上就實現(xiàn)了一個Native控件注入到lua環(huán)境中進行使用。

現(xiàn)有LuaView控件的擴展

上面已經(jīng)解讀了LVImage是如何注冊到Lua環(huán)境中進行使用缆蝉。當(dāng)Lua腳本里setImage 設(shè)置圖片宇葱,傳入?yún)?shù)是url時,圖片是沒有顯示的刊头,查看LVImage的方法會發(fā)現(xiàn)黍瞧,因為LVImage 的 setWebImageUrl 是沒有實現(xiàn)的。故考慮通過繼承的方式擴展LVImage的功能原杂,讓其支持網(wǎng)絡(luò)圖片的加載印颤。

#import "XQImage.h"

#import "LVHeads.h"

#import <SDWebImage/UIImageView+WebCache.h>

@implementation XQImage

-(void) setWebImageUrl:(NSURL*) url finished:(LVLoadFinished) finished{

[self sd_setImageWithURL:url];

}

@end

XQImage 繼承自LVImage,并且重寫了父類的方法 -(void) setWebImageUrl:(NSURL*) url finished:(LVLoadFinished) finished穿肄。(此處采用SDWebImage進行圖片下載展示)

自定義子類實現(xiàn)了年局,但是Lua環(huán)境注冊的還是父類LVImage际看,故,lua腳本初始化Image()矢否,還是會初始化父類的實例仲闽,故無法調(diào)用到子類的圖片下載賦值方法。父類的注冊僵朗,是在LuaView初始化時赖欣,那么LuaView初始化后,需要將子類覆蓋父類注冊到lua環(huán)境中验庙,讓 globalName(“Image”)對應(yīng)的是子類:

self.lv[@"Image"] = [XQImage class];

如此后顶吮,lua腳本 Image() 創(chuàng)建的就是native的XQImage對象。由此實現(xiàn)網(wǎng)絡(luò)圖片的加載和顯示粪薛。

完全自定義類的橋接

上節(jié)通過繼承的方式擴展 LuaView 已封裝的UI控件悴了,并且覆蓋注冊到lua環(huán)境中。那么如何將自定義的一個類违寿,橋接到Lua環(huán)境中使用呢湃交?

正如前面源碼解析,了解了 LuaView封裝的NativeUI 是如何實現(xiàn)的藤巢,所以按部就班巡揍,照著這個邏輯實現(xiàn)自定義類的橋接。其中最關(guān)鍵的是實現(xiàn) LVClassProtocal 協(xié)議的方法 + (int)lvClassDefine:(lua_State *)L globalName:(NSString *)globalName; 來實現(xiàn)指定類及其初始化方法菌瘪,全局函數(shù)注冊到 Lua 環(huán)境中,供 Lua 腳本直接使用阱当。

+(int) lvClassDefine:(lua_State *)L globalName:(NSString*) globalName{

[LVUtil reg:L clas:self cfunc:lvNewItem globalName:globalName defaultName:@"XQItemLuaView"];

const struct luaL_Reg memberFunctions [] = {

{"image",? setIconImage},

{"title",? ? title},

{NULL, NULL}

};

lv_createClassMetaTable(L,META_TABLE_CustomView);

luaL_openlib(L, NULL, [LVBaseView baseMemberFunctions], 0);

luaL_openlib(L, NULL, memberFunctions, 0);

const char* keys[] = { "addView", NULL};// 移除多余API

lv_luaTableRemoveKeys(L, keys );

return 1;

}

XQItemLuaView 是我自定義的一個 UIView 的子類俏扩,遵循 LVProtocal, LVClassProtocal 協(xié)議。其上有一個 ImageView 和 Label弊添。C函數(shù) lvNewItem 用于初始化一個 XQItemLuaView 的對象录淡,setIconImage 用于根據(jù) Lua 腳本傳入的參數(shù),設(shè)置 iconImageView 的圖片展示油坝。 title 為根據(jù)Lua腳本傳入的參數(shù)字符串嫉戚,設(shè)置 titleLabel 的text。

LVClassProtocal 是一個靜態(tài)協(xié)議澈圈,源碼分析中可以看到彬檀,LuaView 加載其擴展類的時候,都是通過初始化 LuaViewCore 時瞬女,遍歷所有需要加載的類窍帝,調(diào)用其 + (int)lvClassDefine:(lua_State *)L globalName:(NSString *)globalName 方法,實現(xiàn)加載诽偷。

而完全自定義的類的加載坤学,最好不要去直接更改其 LuaViewCore 源碼疯坤。所以我創(chuàng)建了一個管理自定義類注冊的操作類 XQRegisterManager 。

#import "XQRegisterManager.h"

#import "XQItemLuaView.h"

@implementation XQRegisterManager

/**

自定義類的注冊管理

@param luaState 狀態(tài)機

*/

+(void)registerClassWithLuaState:(lua_State*)luaState{

[XQItemLuaView lvClassDefine:luaState globalName:@"XQItemLuaView"];

}

@end

在 LuaView/LuaViewController 初始化后深浮,去調(diào)用注冊自定義的類压怠。如:

self.lv = [[LView alloc] initWithFrame:lvRect];

[XQRegisterManager registerClassWithLuaState:self.lv.luaviewCore.l];

self.lvCore = [[LuaViewCore alloc]init];

[XQRegisterManager registerClassWithLuaState:self.lvCore.l];

總結(jié)

以上是我一周時間學(xué)習(xí)LuaView的記錄。從簡單運行一個 Lua腳本開始認(rèn)識這個SDK飞苇,到最后分析源碼菌瘫,來實現(xiàn)自定義類的橋接。下一步的目標(biāo)是玄柠,在此基礎(chǔ)上突梦,研究資源腳本下載實現(xiàn),SDK自帶的debuger工具類的使用羽利,以及當(dāng)腳本出錯或者下載失敗的降級處理(LuaViewSDK 沒有自帶降級處理宫患,所有運行失敗會有錯誤拋出,需要根據(jù)錯誤这弧,自行處理降級還是顯示失敗頁面)等娃闲。

如有紕漏,歡迎指出匾浪,謝謝皇帮!

Demo地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蛋辈,隨后出現(xiàn)的幾起案子属拾,更是在濱河造成了極大的恐慌,老刑警劉巖冷溶,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渐白,死亡現(xiàn)場離奇詭異,居然都是意外死亡逞频,警方通過查閱死者的電腦和手機纯衍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苗胀,“玉大人襟诸,你說我怎么就攤上這事』” “怎么了歌亲?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長堡掏。 經(jīng)常有香客問我应结,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任鹅龄,我火速辦了婚禮揩慕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扮休。我一直安慰自己迎卤,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布玷坠。 她就那樣靜靜地躺著蜗搔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪八堡。 梳的紋絲不亂的頭發(fā)上樟凄,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音兄渺,去河邊找鬼缝龄。 笑死,一個胖子當(dāng)著我的面吹牛挂谍,可吹牛的內(nèi)容都是我干的叔壤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼口叙,長吁一口氣:“原來是場噩夢啊……” “哼炼绘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起妄田,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤俺亮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后疟呐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铅辞,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年萨醒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苇倡。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡富纸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出旨椒,到底是詐尸還是另有隱情晓褪,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布综慎,位于F島的核電站涣仿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜好港,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一愉镰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧钧汹,春花似錦丈探、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至塘秦,卻和暖如春讼渊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背尊剔。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工爪幻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赋兵。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓笔咽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親霹期。 傳聞我的和親對象是個殘疾皇子叶组,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 0. 前言 最近一直在寫Lua腳本,有時候出了問題历造,不知道是Lua層的問題甩十,還是上游的問題,不知道從何下手吭产。于是我...
    ZSpirytus閱讀 2,391評論 0 3
  • 指令集 lua_capture_error_log lua_use_default_type lua_malloc...
    吃瓜的東閱讀 12,000評論 0 2
  • 第一篇 語言 第0章 序言 Lua僅讓你用少量的代碼解決關(guān)鍵問題侣监。 Lua所提供的機制是C不擅長的:高級語言,動態(tài)...
    testfor閱讀 2,670評論 1 7
  • 今天我很羨慕我們班同學(xué)臣淤,因為他們讀書筆記寫的好橄霉,得了獎狀和不同的小本,他們非常開心邑蒋。我有點失落姓蜂,但我想我努...
    碎片幻影閱讀 134評論 0 0