In the access Flutter Android project, an Android layout Flutter

beginning

Flutter in the development, there will always be two unavoidable questions below:

  • Native to flutter migration project, we need access to flutter in the native project
  • flutter project to be used to some of the more mature application, we can not avoid going to use a variety of mature native libraries, such as audio and video like

This article will be on the above two cases, were introduced

Flutter access interface in Android

You need access to flutter in the form module in android project

Create a flutter module

Android into the current project, run the following command in the root directory:

flutter create -t module my_flutter

The above represents the creation of flutter module called my_flutter

After running

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

Also, make sure you are in your project directory android app / build.gradle, there is add the following code:

android {
 compileSdkVersion 28
 defaultConfig {
 ...
 }
 buildTypes {
 ...
 }
 //flutter相关声明
 compileOptions {
 sourceCompatibility 1.8
 targetCompatibility 1.8
 }
}

Then, add the following code settings.gradle under the root directory of the project android

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

Finally, the need to introduce my_flutter in app / build.gradle under android project

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

Here, we are ready to start access to the content of the flutter

But this time there is a need to pay attention, if your android project has been moved to androidx, you may encounter this problem below

In the access Flutter Android project, an Android layout Flutter

This problem is evident because flutter create moudle, did not do androidx conversion, because the command does not support creation of moudle androidx

The following began to solve this problem

To solve the problem caused by androidx

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

# 表示使用 androidx
android.useAndroidX=true
# 表示将第三方库迁移到 androidx
android.enableJetifier=true

The following into my_flutter directory, modify dependent portion of the library in your android project in /my_flutter/.android/Flutter/build.gradle

If the default 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'
}

Will all depend modified to androidx version:

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 on android studio after synchronization

Re-entering your android project /my_flutter/.android/Flutter/src/main/java/io/flutter/facade/ directory below directory of Flutter.java and FlutterFragment.java be modified separately

Modify FlutterFragment.java

Originally dependent as follows

In the access Flutter Android project, an Android layout Flutter

The error part is replaced androidx version

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

Modify Flutter.java

Originally dependent as follows

In the access Flutter Android project, an Android layout Flutter

The error part is replaced androidx version

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

So now, the question androidx brought solved, the following began to prepare a formal access Flutter

In the edit entry flutter

My_flutter into the directory lib directory, you can see there comes main.dart file system, which is a default page counter, we modify part:

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),
 );
 }
}

The inlet replaced by "route1" enter into the naming

The next step is to operate in the android

Access flutter in the android

Android into the 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)
 }

We can see from the above code, we have an event by clicking on a button to show the flutter of the counter page. The actual effect is as follows:

In the access Flutter Android project, an Android layout Flutter

So android access flutter is over, here is the flutter of access android

Flutter access interface in android

We can create a flutter project to test this example

Because the use of kotin, so use the following command

flutter create -a kotlin counter_native

flutter create -a kotlin counter_native

Android Data acquisition

On how to get the data, mainly using MethodChannel

Look at the code in MainActivity 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 callback MethodChannel result, we were screened, if the method name is returned directly getCounterData 100

Then write the following code flutter in:

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;
 });
 }

Results are as follows:

In the access Flutter Android project, an Android layout Flutter

Obtain data on android Here, the following is to get the android's page

Get android layout

Compared to the data, the layout will get the android more complex

Creating android view

In android project which created a flutter in the layout you want to show, and here, we combine the xml file to create the layout, but use the xml way, the case file is not found R will appear, this time the compiler will complain, temporarily not to manage:

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 = "当前Android的Text数值是:${counterData.counterData}"
 result.success(counterData.counterData)
 }
 "decreaseNumber" -> {
 counterData.counterData--
 myText.text = "当前Android的Text数值是:${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("出错", "size无法再小了!", 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("出错", "size无法再大了!", null)
 }
 }
 "setText" -> {
 myText.text = (methodCall.arguments as String)
 result.success(myText.text)
 }
 else -> {
 result.notImplemented();
 }
 }
 }
}

The above CounterData class for storing data created a class:

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

Next, we create a CounterViewFactory class used to get to 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, which is used to register view, the equivalent of initialization entry

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

Once created, a view in MainActivity registered in:

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

Next, it is the flutter of the need to do something

In view of the flutter get android

In flutter inside, I want to get the android's view, need to get through AndroidView

Widget build(BuildContext context) {
 if (Platform.isAndroid) {
 return AndroidView(
 viewType: 'samples.flutter.io/counter_view',
 onPlatformViewCreated: _onPlatformViewCreated,
 );
 }
 return Text(
 '$defaultTargetPlatform 还不支持这个布局');
 }

In onPlatformViewCreated approach, we need to create MethodChannel, method calls for android in writing, 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 is 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,
 );
 }
}

Results are as follows:

In the access Flutter Android project, an Android layout Flutter

Guess you like

Origin blog.51cto.com/14332859/2429223