Develop Flutter applications using flutter_luakit_plugin as the base library
At the beginning of this article we will start by showing the difference between using Flutter_luakit_plugin as a base library development and normal FLUTTER. Since Flutter positioning is a portable UI package, the basic library functions provided by Flutter are not sufficient for complex data applications. The general flutter development mode is shown in the following figure. When Flutter does not meet our needs, Call the native interface using methodChannel and EventChannel.
The development mode using Flutter_luakit_plugin as the base library is shown in the figure below. Lua is used to write the logical layer code and FLUTTER is used to write the UI code. Luakit provides rich support for logical layer development of most apps, including database ORM, thread management, HTTP request, asynchronous socket, timer, notification, JSON, etc. Users only need to write DART code and Lua code, not OC, SWIFT or Java, kotlin code, which dramatically improves code consistency (all running code is cross-platform).
Flutter_luakit_plugin origin
I was excited when Flutter was born, because I had always had a negative view of cross-platform UI development. One of the main reasons for this was the lack of experience consistency. But Flutter solved this problem for the first time, so that a UI developed at one end, no matter how complex, could have a consistent experience at the other end. Cross-platform UI solutions that do not do this actually do not achieve the cross-platform work-saving effect that Flutter does.
Flutter1.0.0 was released and I think all the elements needed for cross-platform mobile development are in place. We tried to do some features with Flutter and one release later we summarized some issues.
-
Flutter is a UI solution. However, a function of Flutter requires a lot of support, including network requests, long connections, short connections, databases, thread control, etc. These aspects are poorly provided in the Flutter ecosystem. There are not as many mature solutions as there are in ios or Android. To overcome this problem, Flutter provides a solution that calls the ios and android interfaces using methodchannel and eventchannel and uses the native, mature solution as the underlying logic. We also solved this problem in the beginning, but later troubles came. Because the methods implemented by MethodChannel and EventChannel are not cross-platform, the data format of Flutter obtained from ios and Android, the timing of event invocation, etc., the implementation of Flutter on the two platforms are different. It’s almost impossible to be completely uniform, so to speak, a feature that works on one end will not work on the other end the first time, and then you have to spend a lot of time debugging and adapting, and then the advantage of cross-platform is gone, and people will keep bickering. Trust me, these conversations will become part of your daily routine.
Ios development: “The interface you wrote on Android doesn’t work on ios”
Android development: “We can run Android, iOS interface is not written right”
Ios development: “Where is wrong, Android wrote the interface, Android help adjust it”
Android developer: “I’m not an ios developer, how do I tune it?”
-
When an existing APP is connected to a flutter, the data and logic in the flutter system are not compatible with the logic of the external native app. To be brief, the business logic written by the flutter system is usually written in dart language. The code written in native Object C, Swift, Java or Kotlin cannot invoke the dart logic without the interface of flutter. This lack of interoperability will result in the failure of data linkage. For example, the native interface needs to realize the data stored in a flutter page. Or the native interface may need to do some pre-loading for the flutter page, which is inconvenient. Mainly in the following figure, it is not allowed to call the flutter interface from the native when the flutter interface is not called.
Previously, I opened source luakit(with luakit origins), a cross-platform solution of pure logic layer, which provides a basic capability for business development, including network request, long connection, short connection, ORM database, thread, notification mechanism, etc. And these capabilities are stable, cross-platform and proven solutions for real businesses.
After making one version of Pure Flutter, I realized that we could use a new development mode for Flutter development, which could avoid the two problems I mentioned above. Our team immediately implemented another version of Flutter + Luakit, which used Flutter as the interface. Write the logic in Lua as follows.
The development efficiency of the new scheme has been greatly improved. To be sure, it has truly realized cross-platform. From page to logic, all the codes of a business are completed by scripts (Dart + LuA) without object C, Swift, Java or Kotlin to write logic. In this way, a business can be moved seamlessly from one end to the other, so I wrote this article to introduce our team’s attempt and open source our flutter_luakit_plugin, so that this development mode can help more FLUTTER development teams.
Detail the development model
Next let’s see how flutter works with Lua to make all the code cross platform. We provide a demo project for your reference.
-
The dart write interface
In the demo, all the UI is written in main.dart, which would be much more complex in real business, but it doesn’t affect our development model.
-
Dart calls the LuA logical interface
FlutterLuakitPlugin.callLuaFun("WeatherManager"."getWeather").then((dynamic d) {
print("getWeather" + d.toString());
setState(() {
weathers = d;
});
});
Copy the code
This code is equivalent to calling the Lua module of WeatherManager, which provides the getWeather method, and returning the data to dart as a Future
require('WeatherManager').getWeather( function (d)
end)
Copy the code
Then the rest of the job is to lua, in Lua you can use all the powerful functions provided by Luakit, most of the functions needed by an app should be provided, and we will continue to expand.
If you’re worried about the dart and Lua data format conversion, don’t worry. All the details are wrapped in Flutter_luakit_plugin, so just use lua as you would dart.
-
Implement all non-UI logic in Lua
This demo(weatherManager.lua) demonstrates how to use Luakit’s related functions, including networking, ORM database, multithreading, data parsing, etc.
-
If there is something that flutter_luakit_plugin does not support, you can implement it by walking back to the methodchannel and eventchannel provided by flutter
How do I access the Flutter_luakit_plugin
After a few months of practice, our team has reduced the cost of accessing flutter_luakit_plugin to a minimum, making it very easy to access. We have published the Flutter_luakit_plugin to the official Flutter plugin repository. First, add a dependency to Pubspec. yaml as other FLUTTER plug-ins do. See the Demo configuration
Flutter_luakit_plugin: ^ 1.0.0Copy the code
Then add the ios dependencies to the ios project’s podfile, as shown in Demo configuration
source 'https://github.com/williamwen1986/LuakitPod.git'
source 'https://github.com/williamwen1986/curl.git'
pod 'curl'.'~ > 1.0.0'
pod 'LuakitPod'.'~ > 1.0.13'
Copy the code
Then add android dependencies to the build.gradle file of the Android project app, refer to demo configuration
repositories {
maven { url "https://jitpack.io" }
}
dependencies {
implementation 'com. Making. Williamwen1986: LuakitJitpack: 1.0.6'
}
Copy the code
Finally, you can use lua scripts by adding import where you need to use them
import 'package:flutter_luakit_plugin/flutter_luakit_plugin.dart';
Copy the code
The default root path for executing lua scripts on Android is Assets/Lua, and the default root path for executing lua scripts on ios is Bundle.
Flutter_luakit_plugin Development environment IDE–AndroidStudio
The officially recommended ides for flutter are androidstudio and visual studio code. We found androidstudio to be more useful during development, so we also developed a luakit plugin for androidstudio, called luakit. The Luakit plug-in provides the following functions.
- Remote Lua debugging
- Use the lookup function
- Skip to function definition
- Jump to the file
- Parameter name Hint
- Automatic code completion
- Code formatting
- Code syntax check
- Standard Lua API auto-completion
- Luakit API auto-completion
Most of the features are not much different from other ides. I won’t go into details here. I will focus on the remote Lua debugging function, because it is a little different from normal debugging ios and Android devices.
Androidstudio installs the Luakit plugin
AndroidStudio->Preference.. ->Plugins->Browse reprositories…
Search for Luakit and install the Luakit plug-in and restart AndroidStudio
Configure the LuA project
Open the Project Struture window
Select Modules, Mark as Sources
Adding a debugger
Select Edit Configurations…
Select plus
Add the Lua Remote (Mobdebug)
Remote Lua debugging
Before we start debugging Lua, we need to add the following line of Lua code to the lua file we want to debug. Then set a breakpoint, you can debug. Lua code has two parameters, the first is the IP address of the computer you are debugging, the second is the debugging port, default is 8172.
require("mobdebug").start("172.25.129.165".8172)
Copy the code
Luakit debugging is through socket to pass debugging information, all debugging machines must be my computer in the same network segment, sometimes may not be able to do, here we give the solution, our daily debugging is also so to solve. First turn your phone on the hot spot, then connect your computer to the hot spot of the phone, now you can ensure that your phone and computer are the same network segment, and then check the IP address of the computer, fill in the Lua code, you can achieve debugging.
Introduction to the API provided by flutter_luakit_plugin
(1) Database ORM operation
This is a powerful feature provided by Flutter_luakit_plugin. It is also the simple and efficient database operation that Flutter lacks. The database ORM function provided by Flutter_luakit_plugin has the following features
- object-oriented
- Automatically create and update table structures
- Internal object cache
- Timed automatic transaction
- Thread-safe, no need to worry about threads at all
For details, please refer to Demo Lua. Here is a brief introduction.
Defining the data model
-- 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")
Copy the code
Insert data
local userTable = Table("user")
local user = userTable({
username = "user1",
password = "abc",
time_create = os.time()
})
user:save()
Copy the code
Update the data
local userTable = Table("user")
local user = userTable.get:primaryKey({"user1"}):first()
user.password = "efg"
user.time_create = os.time()
user:save()
Copy the code
Delete the data
local userTable = Table("user")
local user = userTable.get:primaryKey({"user1"}):first()
user:delete()
Copy the code
Batch Update Data
local userTable = Table("user")
userTable.get:where({age__gt = 40}):update({age = 45})
Copy the code
Deleting Data in Batches
local userTable = Table("user")
userTable.get:where({age__gt = 40}):delete()
Copy the code
Select data
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 -----------")
Copy the code
League table operation
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 ")
Copy the code
(2) Notification mechanism
The notification mechanism provides a low-coupling approach to event interaction, where messages are registered in either Native or Lua or DART, and messages thrown anywhere can be received.
Flutter adds listening messages
void notify(dynamic d) {
}
FlutterLuakitPlugin.addLuaObserver(3, notify);
Copy the code
Flutter unlisten
FlutterLuakitPlugin.removeLuaObserver(3, notify);
Copy the code
Flutter behind the message
FlutterLuakitPlugin.postNotification(3, data);
Copy the code
Lua adds listening message 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);
Copy the code
Lua Discard message Demo code
lua_notification.postNotification(3,
{
lua1 = "lua123",
lua2 = "lua234"
})
Copy the code
Ios Added the demo code for listening messages
_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);
}
Copy the code
Ios Discard message Demo code
post_notification(3, @{@"row":@(2)});
Copy the code
Android added listening message Demo code
LuaNotificationListener listener = new LuaNotificationListener();
INotificationObserver observer = new INotificationObserver() {
@Override
public void onObserve(int type, Object info) {
HashMap<String, Integer> map = (HashMap<String, Integer>)info;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
Log.i("business"."android onObserve");
Log.i("business", entry.getKey());
Log.i("business".""+entry.getValue()); }}}; listener.addObserver(3, observer);
Copy the code
Android discard message Demo code
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("row".new Integer(2));
NotificationHelper.postNotification(3, map);
Copy the code
(3) HTTP request
Flutter itself provides the HTTP request library DIO. However, when the logical interface of the project is intended to be available to both flutter and native, the logical code written by Flutter is not suitable. As mentioned above, native can not call the flutter code at will. Therefore, only Luakit is suitable for this situation. The logical interface written by Lua can be invoked anywhere, including flutter, ios, and Android. Luakit provides the HTTP interface (Demo code) below.
-- 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})
Copy the code
(4) Async socket
Flutter supports only websocket. If your app wants to use the basic socket protocol, you need to use the socket function provided by flutter_luakit_plugin. The demo code can be used to retrieve data from the callback and send the data back to the flutter layer using the notification mechanism mentioned above.
local socket = lua_asyncSocket.create("127.0.0.1".4001)
socket.connectCallback = function (rv)
if rv >= 0 then
print("Connected")
socket:read(a)end
end
socket.readCallback = function (str)
print(str)
timer = lua_timer.createTimer(0)
timer:start(2000.function (a)
socket:write(str)
end)
socket:read(a)end
socket.writeCallback = function (rv)
print("write". rv)end
socket:connect()
Copy the code
(5) JSON parsing
Json is the most common data type. You can use it in demo
local t = cjson.decode(responseStr)
responseStr = cjson.encode(t)
Copy the code
(6) Timer
Timer is often used in the project development of a function, timer we use in the ORM framework lua source code, demo
local _timer
_timer = lua_timer.createTimer(1) / /0Stands for single,1_timer:start(2000.function (a)
end)
_timer:stop()
Copy the code
(7) All general libraries suitable for Lua use are available in flutter_luakit_plugin
The Flutter technology accumulates relevant links
Flutter general base library flutter_luakit_plugin
Flutter_luakit_plugin Example
How to Build the Flutter Engine
Troubleshooting Flutter Engine Memory Leaks
Fixed memory leaks after the Flutter Engine (available directly)
Fix memory leak after the use of Flutter Engine example
Continuously updated…