This article is first published in the wechat public account “Android development journey”, welcome to follow, get more technical dry goods
Wan-android Jetpack VersionAndroid Jetpack architecture for componentized application developmentWelcome to star
Project address of Flutter wan-AndroidFlutter Wan – AndroidWelcome to star
Mixed development application scenarios
At present, there are few applications for the development of pure Flutter in China, and most companies using Flutter development also use hybrid development. So what are the main usage scenarios for hybrid development?
- Join as a separate page. You can jump from the native page to the Flutter page, or from the Flutter page to the native page.
- Embed as part of the page.
Create a Flutter module
Since we are doing hybrid development, we must be working on Android native projects. If the path of the native project is flutter/flutter_hybrid/native, then we need to create the Flutter module in the flutter_hybrid directory above native.
CD flutter/ flutter_module create a flutter that supports AndroidX -- AndroidX -t module flutter_module // Create flutter -t module flutter_module that does not support AndroidXCopy the code
Therefore, when we create modules, we should first determine whether native project already supports AndroidX. If so, we need to add — AndroidX parameter.
After input, the console prints the following:
$ flutter create -t module flutter_module
Creating project flutter_module...
flutter_module/test/widget_test.dart (created)
flutter_module/flutter_module.iml (created)
flutter_module/.gitignore (created)
flutter_module/.metadata (created)
flutter_module/pubspec.yaml (created)
flutter_module/README.md (created)
flutter_module/lib/main.dart (created)
flutter_module/flutter_module_android.iml (created)
flutter_module/.idea/libraries/Flutter_for_Android.xml (created)
flutter_module/.idea/libraries/Dart_SDK.xml (created)
flutter_module/.idea/modules.xml (created)
flutter_module/.idea/workspace.xml (created)
Running "flutter pub get" in flutter_module... 1.2s
Wrote 12 files.
All done!
Your module code is in flutter_module/lib/main.dart.
Copy the code
When we see All done, our project is created. The entire Module directory is basically the same as the native Flutter. It is the host project of Android and iOS, as well as the lib directory and pubspec.yaml file.
Add Flutter Module dependencies
Once the Module project is created, it needs to be added to the Android project. Open the setting.gradle file of your Android project and add the following code:
setBinding(new Binding([gradle: this])) evaluate(new File( settingsDir.parentFile, //flutter_module = 'flutter_module/.android/include_flutter. Groovy ')Copy the code
SetBinding and evaluate allow the Flutter module to have any Flutter plug-ins, including itself, in settings.gradle in a manner similar to: Flutter, package_info, :video_player.
Then open app/build.gradle and add dependencies to the Dependencies TAB:
implementation project(':flutter')
Copy the code
This adds dependencies in two steps. Why is “flutter” added instead of “flutter_module”? Because a folder called Flutter is generated in the Android project directory after the project is compiled, this is what we need to rely on. Note that minSdkVersion in Gradle must be greater than or equal to 16 because this is the lowest version that Flutter supports. Also added to compile using java8. Add this to the Android TAB in app/build.gradle:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
Copy the code
Call to Flutter the module
Once the dependencies are complete we can call the Flutter module to create the UI. Flutter provides two ways to call Flutter. One is createView, which is loaded as a view. The other is createFragment, which is loaded as a fragment in Android.
CreateView way:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // setContentView(R.layout.activity_main); FlutterView flutterView = Flutter.createView(this, getLifecycle(), "initialRoute"); setContentView(flutterView); }}Copy the code
CreateFragment way:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); // Container is the placeholder for activity_main. FrameLayout transaction.replace(R.I.D.C. Ontainer, Flutter. CreateFragment ("initialRoute")); transaction.commit(); }}Copy the code
This loads the app with Flutter’s default home page.
As you can see from the above two sections of code, there is an “initialRoute” parameter that tells the Dart code which widget to display in the Flutter view. Let’s modify the main.dart code in module to load our own page.
We set up two routes to display the route1Widget and route2Widget, and display the alert text when there is no match.
import 'package:flutter/material.dart'; import 'dart:ui'; Void main() => runApp(MyApp(// use window.defaultroutename to obtain the parameters passed from native. window.defaultRouteName, )); class MyApp extends StatelessWidget { final String initParams; MyApp({Key key, this.initParams}) : super(key: key); @override Widget build(BuildContext context) {return MaterialApp(title: 'Flutter_Android mixed development ', theme: ThemeData( primarySwatch: Colors.blue, ), home: HomePage(initParams: initParams), ); } } class HomePage extends StatefulWidget { final String initParams; const HomePage({Key key, this.initParams}) : super(key: key); @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: _widgetRoute(widget.initParams), ), ); }} /// widgetroute (String route) {switch (route) {case "route1": return route1Widget(); case "route2": return route2Widget(); default: return notFoundWidget(); } } Widget route1Widget() { return Center( child: Text( "this is route1Widget", style: TextStyle(color: Colors.red, fontSize: 20), ), ); } Widget route2Widget() { return Center( child: Text( "this is route2Widget", style: TextStyle(color: Colors.blue, fontSize: 20), ), ); } Widget notFoundWidget() {return Center(child: Text(" failed to match route 111", style: TextStyle(fontSize: 40),); }Copy the code
We will now replace the initialRoute parameter when a Flutter is loaded with “route1”. The page will load the route1Widget with “route2”, which will load the route2Widget. Otherwise, the notFoundWidget is displayed. Of course we can pass the route argument directly, but since the argument itself is a string, we can do things. For example, passing a JSON string can do a lot of things? I will not post the demo here, because the logic is basically the same as above, you can try.
Hot restart/reload
When you write a pure Flutter application, you know that the hot restart/reload function is available, but in the process of hybrid development, you will find that the hot restart/reload function is disabled. So how do you turn on hot restart/reload in mixed development?
- First plug into our device or emulator
- Close our App, exit the background, and run the flutter attach command in terminal
$ flutter attach
Waiting for a connection from Flutter on Android SDK built for x86...
Copy the code
At this point, you are waiting for the device to connect. Note that if the computer is connected to multiple devices, you need to use the -d command to specify a device with the id of the device.
Flutter attach -D 'Your device ID'Copy the code
- Then we start our application and see console output:
Done. Syncing files to device Android SDK built for x86... 1,393ms 🔥 To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R". An Observatory debugger and profiler on Android SDK built for x86 is available at: http://127.0.0.1:59354/zRsDBfpesrk=/ For a more detailed help message, press the "h". To detach, press "d". to quit, press "q".Copy the code
This means we have connected successfully. The output log also tells us how to use the hot restart/reload feature.
Enter the following command in Terminal:
R: hot loading; R: hot restart; H: Get help; D: Disconnect; Q: Exit;Copy the code
Both d and Q commands exit debugging. The difference is that D simply disconnects while Q pushes the application back into the background.
Debugging the Dart code
How do we debug the DART code during mixed development as well?
- Shut down our app
- Click the Flutter Attach button on the Android Studio toolbar (Need to install the Flutter and Dart plugin)
- Launch our app
You can then debug the Dart code in mixed development mode just as you would debug the normal Flutter project.
conclusion
This is the basic explanation of how to incorporate the Flutter module into your Android native project, including the creation, dependency, invocation, and debugging of the module. Other things like iOS access to the Flutter module, communication between the Android project and the Flutter project, and communication between the iOS project and the Flutter will be covered in future articles. Because it is too long to write in one piece, friends are tired to read. So there will be at least three more articles to follow. Move hands to pay attention to the public account, instant access to the relevant article push.
All Demo source code has been uploaded to the background, attention to the public account reply “Android mixed development” to get the download link.
If you think the article is good, please share it with your likes. Your comments are definitely the biggest encouragement and support for me.
Many friends said I want to add my personal wechat, pit limited, limited time into the pit.
Recommended reading
Dart Quick Start
A detailed guide to iOS project integration with the Flutter module
A detailed guide to The communication between Android and Flutter