Access Flutter in Android Project and use Android Layout in Flutter

Start

In flutter development, there are always two unavoidable problems:

  • The migration of native projects to flutter requires access to flutter in native projects
  • In order to use some mature applications in flutter project, it is unavoidable to use various mature libraries, such as audio and video.

In this article, we will introduce the above two situations separately.

Accessing flutter interface in Android

flutter needs to be accessed as module in android project

Create a flutter module

Enter the current android project and run the following commands in the root directory:

flutter create -t module my_flutter

The above indicates creating a flutter module named my_flutter

Then run

cd my_flutter
cd .android/
./gradlew flutter:assembleDebug

At the same time, make sure that you add the following code to app/build.gradle in your android project directory:

android {
 compileSdkVersion 28
 defaultConfig {
 ...
 }
 buildTypes {
 ...
 }
 //flutter Statement
 compileOptions {
 sourceCompatibility 1.8
 targetCompatibility 1.8
 }
}

Next, add the following code to settings.gradle in the root directory of the android project

include ':app'
setBinding(new Binding([gradle: this]))
evaluate(new File(
 rootDir.path + '/my_flutter/.android/include_flutter.groovy'
))

Finally, my_flutter needs to be introduced into app/build.gradle under the android project

dependencies {
 ...
 //Import flutter
 implementation project(':flutter')
}

At this point, you can basically start accessing flutter content.

However, there is another problem to be noted at this time. If your android project has been migrated to androidx, you may encounter the following problems

Hand-in-hand teaching you to access Flutter in Android projects and use Android layouts in Flutter

The obvious reason for this problem is that flutter did not convert androidx when creating moudles, because the command to create moudles does not support androidx yet.

Let's begin to solve this problem.

Solving the problems brought about by androidx

First, if your original android project has migrated to androidx, then grale.properties in the root directory must have the following contents

# Represents using androidx
android.useAndroidX=true
# Represents migrating third-party libraries to androidx
android.enableJetifier=true

Now go to my_flutter directory and modify the dependency part of the library in your android project / my_flutter/.android/Flutter/build.gradle

If the default is as follows:

dependencies {
 testImplementation 'junit:junit:4.12'
 implementation 'com.android.support:support-v13:27.1.1'
 implementation 'com.android.support:support-annotations:27.1.1'
}

Modify all dependencies to androidx versions:

dependencies {
 testImplementation 'junit:junit:4.12'
 implementation 'androidx.legacy:legacy-support-v13:1.0.0'
 implementation 'androidx.annotation:annotation:1.0.0'
}

After clicking Sync Now Synchronization on android studio

Go to the following directory and modify Flutter.java and Flutter Fragment. Java respectively under your android project / my_flutter/.android/Flutter/src/main/java/io/flutter/facade / directory

Modify FlutterFragment.java

The original dependence is as follows

image

Replace the error section with the androidx version

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;

Modify Flutter.java

The original dependence is as follows

Hand-in-hand teaching you to access Flutter in Android projects and use Android layouts in Flutter

Replace the error section with the androidx version

import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;

Now that androidx's problems are solved, we're ready to officially access Flutter.

Edit Entry in flutter

When you enter the lib directory in my_flutter directory, you can see the main.dart file that comes with the system. This is the default counter page. We modify part of it:

void main() => runApp(getRouter(window.defaultRouteName));
Widget getRouter(String name) {
 switch (name) {
 case 'route1':
 return MyApp();
 default:
 return Center(
 child: Text('Unknown route: $name', textDirection: TextDirection.ltr),
 );
 }
}

Change the entry to enter by "route1" name

Next up is android.

Accessing flutter in android

Into the android project, in MainActivity, we do the following:

 bt_flutter.setOnClickListener {
 val flutterView = Flutter.createView(
 this@MainActivity,
 lifecycle,
 "route1"
 )
 val layout = ConstraintLayout.LayoutParams(
 ViewGroup.LayoutParams.MATCH_PARENT,
 ViewGroup.LayoutParams.MATCH_PARENT
 )
 layout.leftMargin = 0
 layout.bottomMargin = 26
 addContentView(flutterView, layout)
 }

As you can see from the above code, we show the counter page of flutter by clicking on a button. The actual results are as follows:

image.png

So android access to flutter is over. Here's android access to flutter

Accessing android Interface in Flutter

We can create a new flutter project to test this example

Because kotin is used, the following commands are used

flutter create -a kotlin counter_native

After the project is created, we can start. Before we start, we can first understand how to get the data in android from flutter.

Getting android data

The main way to get data is to use Method Channel.

Take a look at the MainActivity code in android

class MainActivity: FlutterActivity() {
 private val channelName = "samples.flutter.io/counter_native";
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 GeneratedPluginRegistrant.registerWith(this)
 MethodChannel(flutterView, channelNameTwo).setMethodCallHandler { methodCall, result ->
 when(methodCall.method){
 "getCounterData" -> {
 result.success(getCounterData())
 }
 else -> {
 result.notImplemented();
 }
 }
 }
 }
 private fun getCounterData():Int{
 return 100;
 }
}

In the MethodChannel result callback, we filtered and returned 100 directly if the method name was getCounterData.

Next, write the following code in flutter:

static const platform =
 const MethodChannel('samples.flutter.io/counter_native');
void getCounterData() async {
 int data;
 try {
 final int result = await platform.invokeMethod('getCounterData');
 data = result;
 } on PlatformException catch (e) {
 data = -999;
 }
 setState(() {
 counterData = data;
 });
 }

The results are as follows:

image.png

That's all for getting android data. Here's how to get android pages.

Get the layout of android

The layout of android is much more complex than the data.

Creating an android View

In the android project, we create a layout that we want to show in flutter. Here, we combine XML files to create the layout, but using xml, there will be the case that R files can not be found. At this time, the compiler will make an error and leave it alone for the time being:

class CounterView(context: Context, messenger: BinaryMessenger, id: Int)
 : PlatformView, MethodChannel.MethodCallHandler {
 private var methodChannel: MethodChannel =
 MethodChannel(messenger, "samples.flutter.io/counter_view_$id")
 private var counterData: CounterData = CounterData()
 private var view: View = LayoutInflater.from(context).inflate(R.layout.test_layout, null);
 private var myText: TextView
 init {
 methodChannel.setMethodCallHandler(this)
 myText = view.findViewById(R.id.tv_counter)
 }
 override fun getView(): View {
 return view
 }
 override fun dispose() {
 }
 override fun onMethodCall(methodCall: MethodCall, result: MethodChannel.Result) {
 when (methodCall.method) {
 "increaseNumber" -> {
 counterData.counterData++
 myText.text = "current Android Of Text The numerical value is:${counterData.counterData}"
 result.success(counterData.counterData)
 }
 "decreaseNumber" -> {
 counterData.counterData--
 myText.text = "current Android Of Text The numerical value is:${counterData.counterData}"
 result.success(counterData.counterData)
 }
 "decreaseSize" -> {
 if(myText.textSize > 0){
 val size = myText.textSize
 myText.setTextSize(TypedValue.COMPLEX_UNIT_PX,size-1)
 result.success(myText.textSize)
 } else{
 result.error("error", "size Can't be smaller!", null)
 }
 }
 "increaseSize" -> {
 if(myText.textSize < 100){
 val size = myText.textSize
 myText.setTextSize(TypedValue.COMPLEX_UNIT_PX,size+1)
 result.success(myText.textSize)
 } else{
 result.error("error", "size It can't be any bigger!", null)
 }
 }
 "setText" -> {
 myText.text = (methodCall.arguments as String)
 result.success(myText.text)
 }
 else -> {
 result.notImplemented();
 }
 }
 }
}

The CountData class above is a class for storing data creation:

class CounterData(var counterData: Int = 0) {
}

Next, we create a CounterViewFactory class to get the layout:

class CounterViewFactory(private val messenger: BinaryMessenger)
 : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
 override fun create(context: Context, id: Int, o: Any?): PlatformView {
 return CounterView(context, messenger, id)
 }
}

Finally, create a CounterViewPlugin.kt file for registering views, which is equivalent to initializing entries

class CounterViewPlugin{
 fun registerWith(registrar: Registrar) {
 registrar.platformViewRegistry().registerViewFactory("samples.flutter.io/counter_view", CounterViewFactory(registrar.messenger()))
 }
}

After the creation is completed, the view is registered in MainActivity:

override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 CounterViewPlugin().registerWith(flutterView.pluginRegistry.registrarFor("CounterViewPlugin"))
 ...
 }

Next, there are some things that need to be done in flutter

Getting android View in flutter

In flutter, to get an android view, you need to get it through android View.

Widget build(BuildContext context) {
 if (Platform.isAndroid) {
 return AndroidView(
 viewType: 'samples.flutter.io/counter_view',
 onPlatformViewCreated: _onPlatformViewCreated,
 );
 }
 return Text(
 '$defaultTargetPlatform This layout is not yet supported');
 }

In the onPlatform View Created method, we need to create a Method Channel to call the methods written in android. We can encapsulate a Controller to handle these logic:

 final CounterController counterController;
 void _onPlatformViewCreated(int id) {
 if (widget.counterController == null) {
 return;
 }
 widget.counterController.setId(id);
 }

Here's CounterController

typedef void CounterViewCreatedCallBack(CounterController controller);
class CounterController {
 MethodChannel _channel;
 void setId(int id){
 _channel = new MethodChannel('samples.flutter.io/counter_view_$id');
 print("id");
 }
 Future increaseNumber() async {
 final int result = await _channel.invokeMethod(
 'increaseNumber',
 );
 print("result:${result}");
 }
 Future decreaseNumber() async {
 final int result = await _channel.invokeMethod(
 'decreaseNumber',
 );
 }
 Future increaseSize() async {
 final result = await _channel.invokeMethod(
 'increaseSize',
 );
 }
 Future decreaseSize() async {
 final result = await _channel.invokeMethod(
 'decreaseSize',
 );
 }
 Future setText(String text) async {
 final result = await _channel.invokeMethod(
 'setText',text,
 );
 }
}

The results are as follows:

image.png

Last

Share an outline of mobile architecture, including all the technical systems that mobile architects need to master. You can compare your shortcomings or deficiencies to learn and improve in a direction.

Require high-definition architecture diagram and video data and article project source code can join my technical exchange group: 825106898 private chat group hosts and sisters free access

image

Keywords: Android Gradle Java Junit

Added by g-force2k2 on Tue, 06 Aug 2019 11:17:01 +0300