摘要:異步長連接功能也是很多開發所依賴的,只支持協議,如果想使用基礎的協議,那就要使用提供的功能了,使用也非常簡單,,在里面拿到數據后可以使用上文提到的通知機制把數據傳回到層。
使用flutter_luakit_plugin作為基礎庫開發flutter應用
文章開頭我們先開門見山給出使用flutter_luakit_plugin作為基礎庫開發和普通flutter的區別。由于flutter定位是便攜UI包,flutter提供的基礎庫功能是不足以滿足復雜數據的app應用的,一般flutter開發模式如下圖所示,當flutter滿足不了我們的需求的時候,使用methodchannel和eventchannel調用native接口。
而使用flutter_luakit_plugin作為基礎庫的開發模式如下圖所示,用lua來寫邏輯層代碼,用flutter寫UI代碼。luakit 提供了豐富的功能支持,可以支持大部分app的邏輯層開發,包括數據庫orm,線程管理,http請求,異步socket,定時器,通知,json等等。用戶只需要寫dart代碼和lua代碼,不需要寫oc、swift或java、kotlin代碼,從而大幅提升代碼的一致性(所有運行代碼都是跨平臺的)。
flutter_luakit_plugin由來Flutter誕生的時候我很興奮,因為我對跨平臺開發UI的看法一直是不看好的,最主要的原因是無法獲得體驗一致性,但是Flutter前無古人的解決了這個問題,真正做到一端開發的UI,無論多復雜,在另一端是可以得到一致的體驗的,做不到這點的跨平臺UI方案實際上并沒有達到跨平臺節省工作量的效果,Flutter做到了。
Flutter1.0.0 發布了,我認為移動端跨平臺開發所需要所有元素都已經齊備了,我們嘗試使用Flutter做一些功能,一個版本之后我們總結了一些問題。
Flutter是一套UI解決方案,但一個功能除了UI,還需要很多支持,網絡請求,長連接,短連接,數據庫,線程控制等等,這些方面Flutter生態中提供得比較差,沒有ios 或者android那么多成熟的解決方案。Flutter 為了克服這問題,提供了一個解決方案,利用methodchannel和eventchannel調用ios和android的接口,利用原生成熟的方案做底層邏輯支撐。我們一開始也是這樣解決,但后續的麻煩也來了,由于methodchannel和eventchannel實現的方法是不跨平臺的,Flutter從ios和android得到的數據的格式,事件調用的時機等,兩個平臺的實現是不一樣的,基本不可能完全統一,可以這樣說,一個功能在一個端能跑通,在另一個端第一次跑一定跑不通,然后就要花大量的時間進行調試,適配,這樣做之后跨平臺的優勢蕩然無存,大家就會不斷扯皮。相信我,下面的對話會成為你們的日常。
ios開發:“你們android寫的界面ios跑不起來” Android 開發:“我們android能跑啊,iOS接口寫得不對吧” ios開發:“哪里不對,android寫的界面,android幫忙調吧” Android 開發:“我又不是ios開發,我怎么調”
當一個已有的app要接入flutter,必然會產生一種情況,就是flutter體系里面的數據和邏輯,跟外部原生app的邏輯是不通的,簡單說明一下,就是flutter寫的業務邏輯通常是用dart語言寫的,我們在原生用object-c、swift或者java、kotlin寫的代碼是不可以脫離flutter的界面調用dart寫的邏輯的,這種互通性的缺失,會導致很多數據聯動做不到,譬如原生界面要現實一個flutter頁面存下來的數據,或者原生界面要為flutter頁面做一些預加載,這些都很不方便,主要是下圖中,當flutter界面沒調用時,從原生調用flutter接口是不允許的。
之前我曾經開源一個純邏輯層的跨平臺解決方案luakit(附上luakit的起源),里面提供一個業務開發所需要的基本能力,包括網絡請求,長連接,短連接,orm數據庫,線程,通知機制等等,而且這些能力都是穩定的、跨平臺而且經過實際業務驗證過的方案。
做完一個版本純flutter之后,我意識到可以用一種新的開發模式來進行flutter開發,這樣可以避免我上面提到的兩個問題,我們團隊馬上付諸實施,做了另一個版本的flutter+luakit的嘗試,即用flutter做界面,用lua來寫邏輯,結構圖如下。
新的方案開發效率得到極大的提升,不客氣的說真正實現了跨平臺,一個業務,從頁面到邏輯,所有的代碼一氣呵成全部由腳本完成(dart+lua),完全不用object-c、swift或者java、kotlin來寫邏輯,這樣一個業務基本就可以無縫地從一端直接搬到另一端使用,所以我寫了這篇文章來介紹我們團隊的這個嘗試,也把我們的成果flutter_luakit_plugin開源了出來,讓這種開發模式幫助到更多flutter開發團隊。
細說開發模式下一步我們一起看看如何用flutter配合lua實現全部代碼都是跨平臺的。我們提供了一個 demo project,供大家參考。
dart寫界面
在demo中所有的ui都寫在了main.dart,當然在真實業務中肯定復雜很多,但是并不影響我們的開發模式。
dart調用lua邏輯接口
FlutterLuakitPlugin.callLuaFun("WeatherManager", "getWeather").then((dynamic d) { print("getWeather" + d.toString()); setState(() { weathers = d; }); });
上面這段代碼的意思是調用WeatherManager的lua模塊,里面提供的getWeather方法,然后把得到的數據以future的形式返回給dart,上面的代碼相當于調用下面一段lua代碼
require("WeatherManager").getWeather( function (d) end)
然后剩下的事情就到lua,在lua里面可以使用luakit提供的所有強大功能,一個app所需要的絕大部分的功能應該都提供了,而且我們還會不斷擴展。
大家可能會擔心dart和lua的數據格式轉換問題,這個不用擔心,所有細節在flutter_luakit_plugin都已經做好封裝,使用者盡管像使用dart接口那樣去使用lua接口即可。
在lua中實現所有的非UI邏輯
這個demo(WeatherManager.lua)已經演示了如何使用luakit的相關功能,包括,網絡,orm數據庫,多線程,數據解析,等等
如果實在有flutter_luakit_plugin沒有支持的功能,可以走回flutter提供的methodchannel和eventchannel的方式實現
如何接入flutter_luakit_plugin經過了幾個月磨合實踐,我們團隊已經把接入flutter_luakit_plugin的成本降到最低,可以說是非常方便接入了。我們已經把flutter_luakit_plugin發布到flutter官方的插件倉庫。首先,要像其他flutter插件一樣,在pubspec.yaml里面加上依賴,可參考demo配置
flutter_luakit_plugin: ^1.0.0
然后在ios項目的podfile加上ios的依賴,可參考demo配置
source "https://github.com/williamwen1986/LuakitPod.git" source "https://github.com/williamwen1986/curl.git" pod "curl", "~> 1.0.0" pod "LuakitPod", "~> 1.0.13"
然后在android項目app的build.gradle文件加上android的依賴,可參考demo配置
repositories { maven { url "https://jitpack.io" } } dependencies { implementation "com.github.williamwen1986:LuakitJitpack:1.0.6" }
最后,在需要使用的地方加上import就可以使用lua腳本了
import "package:flutter_luakit_plugin/flutter_luakit_plugin.dart";
lua腳本我們默認的執行根路徑在android是 assets/lua,ios默認的執行根路徑是Bundle路徑。
flutter_luakit_plugin開發環境IDE--AndroidStudioflutter 官方推薦的IDE是androidstudio和visual studio code。我們在開發中覺得androidstudio更好用,所有我們同步也開發了luakit的androidstudio
插件,名字就叫luakit。luakit插件提供了以下的一些功能。
遠程lua調試
查找函數使用
跳到函數定義
跳到文件
參數名字提示
代碼自動補全
代碼格式化
代碼語法檢查
標準lua api自動補全
luakit api自動補全
大部分功能,跟其他IDE沒太多差別,這里我就不細講了,我重點講一下遠程lua調試功能,因為這個跟平時調試ios和android設備有點不一樣,下面我們詳細介紹androidstudio luakit插件的使用。
androidstudio安裝luakit插件
AndroidStudio->Preference..->Plugins->Browse reprositories...
搜索Luakit并安裝Luakit插件然后重啟androidstudio
配置lua項目
打開 Project Struture 窗口
選擇 Modules、 Mark as Sources
添加調試器
選擇 Edit Configurations ...
Select plus
添加Lua Remote(Mobdebug)
遠程lua調試
在開始調試lua之前,我們要在需要調試的lua文件加上下面一句lua代碼。然后設上斷點,即可調試。lua代碼里面有兩個參數,第一個是你調試用的電腦的ip地址,第二個是調試端口,默認是8172。
require("mobdebug").start("172.25.129.165", 8172)
luakit的調試是通過socket來傳遞調試信息的,所有調試機器務必我電腦保持在同一網段,有時候可能做不到,這里我們給出一下辦法解決,我們日常調試也是這樣解決的。首先讓你的手機開熱點,然后你的電腦連上手機的熱點,現在就可以保證你的手機和電腦是同一網段了,然后查看電腦的ip地址,填到lua代碼上,就可以實現調試了。
flutter_luakit_plugin提供的api介紹(1) 數據庫orm操作
這是flutter_luakit_plugin里面提供的一個強大的功能,也是flutter現在最缺的,簡單高效的數據庫操作,flutter_luakit_plugin提供的數據庫orm功能有以下特征
面向對象
自動創建和更新表結構
自帶內部對象緩存
定時自動transaction
線程安全,完全不用考慮線程問題
具體可參考demo lua,下面只做簡單介紹。
定義數據模型
-- Add the define table to dbData.lua -- Luakit provide 7 colum types -- IntegerField to sqlite integer -- RealField to sqlite real -- BlobField to sqlite blob -- CharField to sqlite varchar -- TextField to sqlite text -- BooleandField to sqlite bool -- DateTimeField to sqlite integer user = { __dbname__ = "test.db", __tablename__ = "user", username = {"CharField",{max_length = 100, unique = true, primary_key = true}}, password = {"CharField",{max_length = 50, unique = true}}, age = {"IntegerField",{null = true}}, job = {"CharField",{max_length = 50, null = true}}, des = {"TextField",{null = true}}, time_create = {"DateTimeField",{null = true}} }, -- when you use, you can do just like below local Table = require("orm.class.table") local userTable = Table("user")
插入數據
local userTable = Table("user") local user = userTable({ username = "user1", password = "abc", time_create = os.time() }) user:save()
更新數據
local userTable = Table("user") local user = userTable.get:primaryKey({"user1"}):first() user.password = "efg" user.time_create = os.time() user:save()
刪除數據
local userTable = Table("user") local user = userTable.get:primaryKey({"user1"}):first() user:delete()
批量更新數據
local userTable = Table("user") userTable.get:where({age__gt = 40}):update({age = 45})
批量刪除數據
local userTable = Table("user") userTable.get:where({age__gt = 40}):delete()
select數據
local userTable = Table("user") local users = userTable.get:all() print("select all -----------") local user = userTable.get:first() print("select first -----------") users = userTable.get:limit(3):offset(2):all() print("select limit offset -----------") users = userTable.get:order_by({desc("age"), asc("username")}):all() print("select order_by -----------") users = userTable.get:where({ age__lt = 30, age__lte = 30, age__gt = 10, age__gte = 10, username__in = {"first", "second", "creator"}, password__notin = {"testpasswd", "new", "hello"}, username__null = false }):all() print("select where -----------") users = userTable.get:where({"scrt_tw",30},"password = ? AND age < ?"):all() print("select where customs -----------") users = userTable.get:primaryKey({"first","randomusername"}):all() print("select primaryKey -----------")
聯表操作
local userTable = Table("user") local newsTable = Table("news") local user_group = newsTable.get:join(userTable):all() print("join foreign_key") user_group = newsTable.get:join(userTable,"news.create_user_id = user.username AND user.age < ?", {20}):all() print("join where ") user_group = newsTable.get:join(userTable,nil,nil,nil,{create_user_id = "username", title = "username"}):all() print("join matchColumns ")
(2) 通知機制
通知機制提供了一個低耦合的事件互通方法,即在原生或者lua或者dart注冊消息,在任何地方拋出的消息都可以接收到。
Flutter 添加監聽消息
void notify(dynamic d) { } FlutterLuakitPlugin.addLuaObserver(3, notify);
Flutter 取消監聽
FlutterLuakitPlugin.removeLuaObserver(3, notify);
Flutter拋消息
FlutterLuakitPlugin.postNotification(3, data);
lua 添加監聽消息demo code
local listener lua_notification.createListener(function (l) listener = l listener:AddObserver(3, function (data) print("lua Observer") if data then for k,v in pairs(data) do print("lua Observer"..k..v) end end end ) end);
lua拋消息demo code
lua_notification.postNotification(3, { lua1 = "lua123", lua2 = "lua234" })
ios 添加監聽消息demo code
_notification_observer.reset(new NotificationProxyObserver(self)); _notification_observer->AddObserver(3); - (void)onNotification:(int)type data:(id)data { NSLog(@"object-c onNotification type = %d data = %@", type , data); }
ios拋消息demo code
post_notification(3, @{@"row":@(2)});
android 添加監聽消息demo code
LuaNotificationListener listener = new LuaNotificationListener(); INotificationObserver observer = new INotificationObserver() { @Override public void onObserve(int type, Object info) { HashMapmap = (HashMap )info; for (Map.Entry entry : map.entrySet()) { Log.i("business", "android onObserve"); Log.i("business", entry.getKey()); Log.i("business",""+entry.getValue()); } } }; listener.addObserver(3, observer);
android拋消息demo code
HashMapmap = new HashMap (); map.put("row", new Integer(2)); NotificationHelper.postNotification(3, map);
(3) http request
flutter本身提供了http請求庫dio,不過當項目的邏輯接口想在flutter,原生native都可用的情況下,flutter寫的邏輯代碼就不太合適了,原因上文已經提到,原生native是不可以隨意調用flutter代碼的,所以遇到這種情況,只有luakit合適,lua寫的邏輯接口可以在所有地方調用,flutter 、ios、android都可以方便的使用lua代碼,下面給出luakit提供的http接口,demo code。
-- url , the request url -- isPost, boolean value represent post or get -- uploadContent, string value represent the post data -- uploadPath, string value represent the file path to post -- downloadPath, string value to tell where to save the response -- headers, tables to tell the http header -- socketWatcherTimeout, int value represent the socketTimeout -- onResponse, function value represent the response callback -- onProgress, function value represent the onProgress callback lua_http.request({ url = "http://tj.nineton.cn/Heart/index/all?city=CHSH000000", onResponse = function (response) end})
(4) Async socket
異步socket長連接功能也是很多app開發所依賴的,flutter只支持websocket協議,如果app想使用基礎的socket協議,那就要使用flutter_luakit_plugin提供的socket功能了,使用也非常簡單,demo code,在callback里面拿到數據后可以使用上文提到的通知機制把數據傳回到flutter層。
local socket = lua_asyncSocket.create("127.0.0.1",4001) socket.connectCallback = function (rv) if rv >= 0 then print("Connected") socket:read() end end socket.readCallback = function (str) print(str) timer = lua_timer.createTimer(0) timer:start(2000,function () socket:write(str) end) socket:read() end socket.writeCallback = function (rv) print("write" .. rv) end socket:connect()
(5) json 解析
json是最常用數據類型,使用可參考demo
local t = cjson.decode(responseStr) responseStr = cjson.encode(t)
(6) 定時器timer
定時器也是項目開發中經常用到的一個功能,定時器我們在orm框架的lua源碼里面有用到,demo
local _timer _timer = lua_timer.createTimer(1)//0代表單次,1代表重復 _timer:start(2000,function () end) _timer:stop()
(7) 還有所有普通適合lua用的庫都可以在flutter_luakit_plugin使用
flutter技術積累相關鏈接flutter通用基礎庫flutter_luakit_plugin
flutter_luakit_plugin使用例子
《手把手教你編譯Flutter engine》
《手把手教你解決 Flutter engine 內存漏》
修復內存泄漏后的flutter engine(可直接使用)
修復內存泄漏后的flutter engine使用例子
持續更新中...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/72893.html
閱讀 3174·2021-11-23 09:51
閱讀 687·2021-10-14 09:43
閱讀 3209·2021-09-06 15:00
閱讀 2410·2019-08-30 15:54
閱讀 2564·2019-08-30 13:58
閱讀 1852·2019-08-29 13:18
閱讀 1384·2019-08-27 10:58
閱讀 514·2019-08-27 10:53