成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Flutter通用基礎(chǔ)庫flutter_luakit_plugin

Ashin / 3222人閱讀

摘要:異步長連接功能也是很多開發(fā)所依賴的,只支持協(xié)議,如果想使用基礎(chǔ)的協(xié)議,那就要使用提供的功能了,使用也非常簡單,,在里面拿到數(shù)據(jù)后可以使用上文提到的通知機制把數(shù)據(jù)傳回到層。

使用flutter_luakit_plugin作為基礎(chǔ)庫開發(fā)flutter應(yīng)用

文章開頭我們先開門見山給出使用flutter_luakit_plugin作為基礎(chǔ)庫開發(fā)和普通flutter的區(qū)別。由于flutter定位是便攜UI包,flutter提供的基礎(chǔ)庫功能是不足以滿足復(fù)雜數(shù)據(jù)的app應(yīng)用的,一般flutter開發(fā)模式如下圖所示,當(dāng)flutter滿足不了我們的需求的時候,使用methodchannel和eventchannel調(diào)用native接口。

而使用flutter_luakit_plugin作為基礎(chǔ)庫的開發(fā)模式如下圖所示,用lua來寫邏輯層代碼,用flutter寫UI代碼。luakit 提供了豐富的功能支持,可以支持大部分app的邏輯層開發(fā),包括數(shù)據(jù)庫orm,線程管理,http請求,異步socket,定時器,通知,json等等。用戶只需要寫dart代碼和lua代碼,不需要寫oc、swift或java、kotlin代碼,從而大幅提升代碼的一致性(所有運行代碼都是跨平臺的)。

flutter_luakit_plugin由來

Flutter誕生的時候我很興奮,因為我對跨平臺開發(fā)UI的看法一直是不看好的,最主要的原因是無法獲得體驗一致性,但是Flutter前無古人的解決了這個問題,真正做到一端開發(fā)的UI,無論多復(fù)雜,在另一端是可以得到一致的體驗的,做不到這點的跨平臺UI方案實際上并沒有達到跨平臺節(jié)省工作量的效果,F(xiàn)lutter做到了。

Flutter1.0.0 發(fā)布了,我認為移動端跨平臺開發(fā)所需要所有元素都已經(jīng)齊備了,我們嘗試使用Flutter做一些功能,一個版本之后我們總結(jié)了一些問題。

Flutter是一套UI解決方案,但一個功能除了UI,還需要很多支持,網(wǎng)絡(luò)請求,長連接,短連接,數(shù)據(jù)庫,線程控制等等,這些方面Flutter生態(tài)中提供得比較差,沒有ios 或者android那么多成熟的解決方案。Flutter 為了克服這問題,提供了一個解決方案,利用methodchannel和eventchannel調(diào)用ios和android的接口,利用原生成熟的方案做底層邏輯支撐。我們一開始也是這樣解決,但后續(xù)的麻煩也來了,由于methodchannel和eventchannel實現(xiàn)的方法是不跨平臺的,F(xiàn)lutter從ios和android得到的數(shù)據(jù)的格式,事件調(diào)用的時機等,兩個平臺的實現(xiàn)是不一樣的,基本不可能完全統(tǒng)一,可以這樣說,一個功能在一個端能跑通,在另一個端第一次跑一定跑不通,然后就要花大量的時間進行調(diào)試,適配,這樣做之后跨平臺的優(yōu)勢蕩然無存,大家就會不斷扯皮。相信我,下面的對話會成為你們的日常。

ios開發(fā):“你們android寫的界面ios跑不起來”

Android 開發(fā):“我們android能跑啊,iOS接口寫得不對吧”

ios開發(fā):“哪里不對,android寫的界面,android幫忙調(diào)吧”

Android 開發(fā):“我又不是ios開發(fā),我怎么調(diào)”


當(dāng)一個已有的app要接入flutter,必然會產(chǎn)生一種情況,就是flutter體系里面的數(shù)據(jù)和邏輯,跟外部原生app的邏輯是不通的,簡單說明一下,就是flutter寫的業(yè)務(wù)邏輯通常是用dart語言寫的,我們在原生用object-c、swift或者java、kotlin寫的代碼是不可以脫離flutter的界面調(diào)用dart寫的邏輯的,這種互通性的缺失,會導(dǎo)致很多數(shù)據(jù)聯(lián)動做不到,譬如原生界面要現(xiàn)實一個flutter頁面存下來的數(shù)據(jù),或者原生界面要為flutter頁面做一些預(yù)加載,這些都很不方便,主要是下圖中,當(dāng)flutter界面沒調(diào)用時,從原生調(diào)用flutter接口是不允許的。

之前我曾經(jīng)開源一個純邏輯層的跨平臺解決方案luakit(附上luakit的起源),里面提供一個業(yè)務(wù)開發(fā)所需要的基本能力,包括網(wǎng)絡(luò)請求,長連接,短連接,orm數(shù)據(jù)庫,線程,通知機制等等,而且這些能力都是穩(wěn)定的、跨平臺而且經(jīng)過實際業(yè)務(wù)驗證過的方案。

做完一個版本純flutter之后,我意識到可以用一種新的開發(fā)模式來進行flutter開發(fā),這樣可以避免我上面提到的兩個問題,我們團隊馬上付諸實施,做了另一個版本的flutter+luakit的嘗試,即用flutter做界面,用lua來寫邏輯,結(jié)構(gòu)圖如下。

新的方案開發(fā)效率得到極大的提升,不客氣的說真正實現(xiàn)了跨平臺,一個業(yè)務(wù),從頁面到邏輯,所有的代碼一氣呵成全部由腳本完成(dart+lua),完全不用object-c、swift或者java、kotlin來寫邏輯,這樣一個業(yè)務(wù)基本就可以無縫地從一端直接搬到另一端使用,所以我寫了這篇文章來介紹我們團隊的這個嘗試,也把我們的成果flutter_luakit_plugin開源了出來,讓這種開發(fā)模式幫助到更多flutter開發(fā)團隊。

細說開發(fā)模式

下一步我們一起看看如何用flutter配合lua實現(xiàn)全部代碼都是跨平臺的。我們提供了一個 demo project,供大家參考。

dart寫界面

在demo中所有的ui都寫在了main.dart,當(dāng)然在真實業(yè)務(wù)中肯定復(fù)雜很多,但是并不影響我們的開發(fā)模式。

dart調(diào)用lua邏輯接口

FlutterLuakitPlugin.callLuaFun("WeatherManager", "getWeather").then((dynamic d) {
  print("getWeather" + d.toString());
  setState(() {
    weathers = d;
  });
});

上面這段代碼的意思是調(diào)用WeatherManager的lua模塊,里面提供的getWeather方法,然后把得到的數(shù)據(jù)以future的形式返回給dart,上面的代碼相當(dāng)于調(diào)用下面一段lua代碼

require("WeatherManager").getWeather( function (d) 
   
end)

然后剩下的事情就到lua,在lua里面可以使用luakit提供的所有強大功能,一個app所需要的絕大部分的功能應(yīng)該都提供了,而且我們還會不斷擴展。

大家可能會擔(dān)心dart和lua的數(shù)據(jù)格式轉(zhuǎn)換問題,這個不用擔(dān)心,所有細節(jié)在flutter_luakit_plugin都已經(jīng)做好封裝,使用者盡管像使用dart接口那樣去使用lua接口即可。

在lua中實現(xiàn)所有的非UI邏輯

這個demo(WeatherManager.lua)已經(jīng)演示了如何使用luakit的相關(guān)功能,包括,網(wǎng)絡(luò),orm數(shù)據(jù)庫,多線程,數(shù)據(jù)解析,等等

如果實在有flutter_luakit_plugin沒有支持的功能,可以走回flutter提供的methodchannel和eventchannel的方式實現(xiàn)

如何接入flutter_luakit_plugin

經(jīng)過了幾個月磨合實踐,我們團隊已經(jīng)把接入flutter_luakit_plugin的成本降到最低,可以說是非常方便接入了。我們已經(jīng)把flutter_luakit_plugin發(fā)布到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腳本我們默認的執(zhí)行根路徑在android是 assets/lua,ios默認的執(zhí)行根路徑是Bundle路徑。

flutter_luakit_plugin開發(fā)環(huán)境IDE--AndroidStudio

flutter 官方推薦的IDE是androidstudio和visual studio code。我們在開發(fā)中覺得androidstudio更好用,所有我們同步也開發(fā)了luakit的androidstudio
插件,名字就叫l(wèi)uakit。luakit插件提供了以下的一些功能。

遠程lua調(diào)試

查找函數(shù)使用

跳到函數(shù)定義

跳到文件

參數(shù)名字提示

代碼自動補全

代碼格式化

代碼語法檢查

標(biāo)準lua api自動補全

luakit api自動補全

大部分功能,跟其他IDE沒太多差別,這里我就不細講了,我重點講一下遠程lua調(diào)試功能,因為這個跟平時調(diào)試ios和android設(shè)備有點不一樣,下面我們詳細介紹androidstudio luakit插件的使用。

androidstudio安裝luakit插件

AndroidStudio->Preference..->Plugins->Browse reprositories...

搜索Luakit并安裝Luakit插件然后重啟androidstudio

配置lua項目

打開 Project Struture 窗口

選擇 Modules、 Mark as Sources

添加調(diào)試器

選擇 Edit Configurations ...

Select plus

添加Lua Remote(Mobdebug)

遠程lua調(diào)試

在開始調(diào)試lua之前,我們要在需要調(diào)試的lua文件加上下面一句lua代碼。然后設(shè)上斷點,即可調(diào)試。lua代碼里面有兩個參數(shù),第一個是你調(diào)試用的電腦的ip地址,第二個是調(diào)試端口,默認是8172。

require("mobdebug").start("172.25.129.165", 8172)

luakit的調(diào)試是通過socket來傳遞調(diào)試信息的,所有調(diào)試機器務(wù)必我電腦保持在同一網(wǎng)段,有時候可能做不到,這里我們給出一下辦法解決,我們?nèi)粘U{(diào)試也是這樣解決的。首先讓你的手機開熱點,然后你的電腦連上手機的熱點,現(xiàn)在就可以保證你的手機和電腦是同一網(wǎng)段了,然后查看電腦的ip地址,填到lua代碼上,就可以實現(xiàn)調(diào)試了。

flutter_luakit_plugin提供的api介紹

(1) 數(shù)據(jù)庫orm操作

這是flutter_luakit_plugin里面提供的一個強大的功能,也是flutter現(xiàn)在最缺的,簡單高效的數(shù)據(jù)庫操作,flutter_luakit_plugin提供的數(shù)據(jù)庫orm功能有以下特征

面向?qū)ο?/p>

自動創(chuàng)建和更新表結(jié)構(gòu)

自帶內(nèi)部對象緩存

定時自動transaction

線程安全,完全不用考慮線程問題

具體可參考demo lua,下面只做簡單介紹。

定義數(shù)據(jù)模型

-- 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")

插入數(shù)據(jù)

local userTable = Table("user")
local user = userTable({
    username = "user1",
    password = "abc",
    time_create = os.time()
})
user:save()

更新數(shù)據(jù)

local userTable = Table("user")
local user = userTable.get:primaryKey({"user1"}):first()
user.password = "efg"
user.time_create = os.time()
user:save()

刪除數(shù)據(jù)

local userTable = Table("user")
local user = userTable.get:primaryKey({"user1"}):first()
user:delete()

批量更新數(shù)據(jù)

local userTable = Table("user")
userTable.get:where({age__gt = 40}):update({age = 45})

批量刪除數(shù)據(jù)

local userTable = Table("user")
userTable.get:where({age__gt = 40}):delete()

select數(shù)據(jù)

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 -----------")

聯(lián)表操作

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 添加監(jiān)聽消息

void notify(dynamic d) {

}

FlutterLuakitPlugin.addLuaObserver(3, notify);

Flutter 取消監(jiān)聽

FlutterLuakitPlugin.removeLuaObserver(3, notify);

Flutter拋消息

FlutterLuakitPlugin.postNotification(3, data);

lua 添加監(jiān)聽消息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 添加監(jiān)聽消息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 添加監(jiān)聽消息demo code

LuaNotificationListener  listener = new LuaNotificationListener();
INotificationObserver  observer = new INotificationObserver() {
    @Override
    public void onObserve(int type, Object info) {
        HashMap map = (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

HashMap map = new HashMap();
map.put("row", new Integer(2));
NotificationHelper.postNotification(3, map);

(3) http request

flutter本身提供了http請求庫dio,不過當(dāng)項目的邏輯接口想在flutter,原生native都可用的情況下,flutter寫的邏輯代碼就不太合適了,原因上文已經(jīng)提到,原生native是不可以隨意調(diào)用flutter代碼的,所以遇到這種情況,只有l(wèi)uakit合適,lua寫的邏輯接口可以在所有地方調(diào)用,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開發(fā)所依賴的,flutter只支持websocket協(xié)議,如果app想使用基礎(chǔ)的socket協(xié)議,那就要使用flutter_luakit_plugin提供的socket功能了,使用也非常簡單,demo code,在callback里面拿到數(shù)據(jù)后可以使用上文提到的通知機制把數(shù)據(jù)傳回到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是最常用數(shù)據(jù)類型,使用可參考demo

local t = cjson.decode(responseStr)

responseStr = cjson.encode(t)

(6) 定時器timer

定時器也是項目開發(fā)中經(jīng)常用到的一個功能,定時器我們在orm框架的lua源碼里面有用到,demo

local _timer

_timer = lua_timer.createTimer(1)//0代表單次,1代表重復(fù)

_timer:start(2000,function ()
    
end)

_timer:stop()

(7) 還有所有普通適合lua用的庫都可以在flutter_luakit_plugin使用

flutter技術(shù)積累相關(guān)鏈接

flutter通用基礎(chǔ)庫flutter_luakit_plugin

flutter_luakit_plugin使用例子

《手把手教你編譯Flutter engine》

《手把手教你解決 Flutter engine 內(nèi)存漏》

修復(fù)內(nèi)存泄漏后的flutter engine(可直接使用)

修復(fù)內(nèi)存泄漏后的flutter engine使用例子

持續(xù)更新中...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/72893.html

相關(guān)文章

發(fā)表評論

0條評論

Ashin

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<