Related articles in this series:
Flutter thermal update and dynamic UI generation
Lua 15 Minutes quick Start (PART 1)
Lua 15 minutes quick Start (II)
Lua and C language call each other
Dart and Lua invocation in LuaDardo
The problem
Because the Dart language turns off reflection on Flutter and the language itself lacks dynamic capabilities, it is difficult to implement thermal updates or dynamic UI on Flutter.
There are some dynamic solutions:
- Update with native framework
- Bridge dynamic scripting languages
- Modified engine (Dynamic Bridge Enhancement)
- XML/JSON configuration UI
The above scheme, in my opinion, is not desirable! The reasons will be analyzed here.
Using native framework updates is essentially updating the binaries associated with the Flutter framework. The products of Flutter application include libflutter. So, libapp.so and flutterAssets. These products can be dynamically delivered and loaded through the native Android platform network request to achieve dynamic updates.
So why not? The main reason is that the iOS App Store does not allow dynamic delivery and loading of binaries, including dynamic libraries, so this solution can only be implemented on Android. One of the most important things about learning and using Flutter is that we need to think cross-platform. Of course, this requires that we have a broad range of technologies that are not as localized as native development. When we consider a Flutter technology solution, the primary consideration is whether the Flutter can be used in general. If it cannot be used in general and can only be used at one end, then the solution is meaningless. The advantage and vitality of Flutter is that it is cross-platform. Any solution that makes Flutter not cross-platform would be better to develop Flutter using native technology, which is mature and fast. It would be a waste of life to bother with Flutter.
No matter how far we go, never forget why we set out!
Let’s take a look at bridging dynamic scripting languages. It’s basically packaging a dynamic scripting language Runtime, currently there’s packaging JavaScript, there’s packaging Lua. These runtimes are essentially a dynamic library packaged into C that looks like it could work, but interacting with the Dart language is difficult. Dart currently has a very weak FFI interface and is not as mature as Java’s JNI. Dart is usually only able to call C, and IT is very difficult for C to call Dart in reverse, so it is not interoperable, but one-way. Then, bridging the Dart language with FFI to interoperate with the target language (JS or Lua) is basically not desirable.
Switching direction again, is it possible to bind scripting language Runtime through Java’s JNI? Bridging Java and scripting languages via JNI is a viable option on Android native, and a good example is the Kivy framework for Python. Kivy can dynamically generate the UI from Python code, but as a Flutter, the target language is Dart instead of Java. The scripting language can easily reflect Java classes, but it is still difficult to interact with Dart. With lots of frequent operations, performance is an issue. The code is also inflexible.
In addition to this, there is an enhancement, which is to modify the Flutter engine. The Dart language virtual machine itself is developed in C++, and it should be easy for scripting languages to interact with Dart through C/C++, just as Java JNI does, if only because the Dart virtual machine does not expose the INTERNAL C++ interface. By modifying the engine to expose the interface, scripting languages can call Dart classes directly. But this option is even less desirable. The Dart language itself currently iterates frequently and changes a lot, and its virtual machines are so complex that it’s almost impossible to maintain the engine branches that you pull.
Finally, let’s look at a scenario for dynamically generating UI based on XML/JSON configuration files. This scheme is actually feasible for some interfaces where local styles may change frequently, as well as for application themes. Its main problem lies in its single function, can only be specific to the template of the UI, and cannot write logic, inflexible.
explore
Some of the main ideas for dynamic renewal have been analyzed above, and here are the solutions I am exploring. That’s the LuaDardo library.
LuaDardo is the Lua virtual machine written by me in Dart language. Its name is made up of two words in Portuguese, which can be translated as “Dart in the moon”.
Lua itself, which means moon in Portuguese, is a compact high-performance scripting language developed by The Brazilians with the goal of embedding in other host languages. The language is mostly used for game development, with Lua scripting the business logic and then calling the underlying C++ game engine for rendering.
The Lua language is exquisitely designed to interoperate with the host language through a stack. LuaDardo writes the Lua virtual machine directly in the Dart language, which allows us to interoperate with The Dart language in a high-performance manner. Just wrap the Widgets of Flutter and bind the Dart class to Lua to write the UI using Lua scripts.
In addition, LuaDardo is directly based on Dart and naturally has cross-platform capabilities that can be used wherever Flutter exists. Even the desktop application of Flutter has this dynamic scripting capability.
LuaDardo itself is a VIRTUAL machine based on Dart language. We need to write the Flutter interface with Lua, and also need to encapsulate and extend the Flutter controls.
Flutter_lua_dardo is one such extension library. This library is primarily used to wrap the Flutter interface and controls, which enables Flutter to dynamically update and generate the interface using remote scripts where frequent UI style changes are required.
Please note that Flutter_lua_Dardo is only an experimental exploration. It encapsulates only a few simple widgets. Others are welcome to explore and package more widgets for Lua.
In addition, LuaDardo library has completed most of the work, but Lua’s own standard library has not been fully written, coprogramming library, OS library, IO library, etc.
example
usage
Create a new Lua script test. Lua:
function getContent1(a)
return Row:new({
children={
GestureDetector:new({
onTap=function(a)
flutter.debugPrint("--------------onTap--------------")
end,
child=Text:new("click here")}),
Text:new("label1"),
Text:new("label2"),
Text:new("label3"),
},
mainAxisAlign=MainAxisAlign.spaceEvenly,
})
end
function getContent2(a)
return Column:new({
children={
Row:new({
children={Text:new("Hello"),Text:new("Flutter")},
mainAxisAlign=MainAxisAlign.spaceAround
}),
Image:network('https://gitee.com/arcticfox1919/ImageHosting/raw/master/img/flutter_lua_test.png'
,{fit=BoxFit.cover})
},
mainAxisSize=MainAxisSize.min,
crossAxisAlign=CrossAxisAlign.center
})
end
Copy the code
Add dependency pubspec.yaml
dependencies:
flutter_lua_dardo: ^ hundreds
Copy the code
Add the Dart code:
class _MyHomePageState extends State<MyHomePage> {
LuaState _ls;
bool isChange = false;
@override
void initState() {
loadLua();
super.initState();
}
// Load the Lua vm
void loadLua() async {
String src = await rootBundle.loadString('assets/test.lua');
try {
LuaState ls = LuaState.newState();
ls.openLibs();
FlutterLua.open(ls);
FlutterWidget.open(ls);
ls.doString(src);
setState(() {
_ls = ls;
});
} catch (e) {
print(e); }}@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: _ls == null
? CircularProgressIndicator()
// Call Lua to create the UI
: FlutterWidget.findViewByName<Widget>(
_ls, isChange ? "getContent2" : "getContent1"), ), floatingActionButton: FloatingActionButton( child: Icon(CupertinoIcons.arrow_swap), onPressed: (){ setState(() { isChange = ! isChange; }); },),); }}Copy the code
To see how to bind the Dart class to Lua, you can look at thisThe sample.
For the LuaDardo library, see here.
Video course
For more information about the blogger’s full stack development of Flutter, click here
Follow my official account: The path of programming from 0 to 1