在 Flutter App 中编写自定义平台特定代码[Method Channel]

前言

学习如何编写自定义平台代码,并将其连接到 flutter 应用程序中

Flutter 使用了一个灵活的系统,允许您使用直接与这些 API 协作的语言调用特定于平台的 API:

  • 在 Android 上使用 Kotlin 或 Java
  • IOS 上的 Swift 或 Objective-C
  • Windows 下的 C + +
  • 在 macOS 上的 Objective-C
  • Linux 上的 C 语言

正文

下面的解释来自 Flutter 官方文档,解释 Method Channel 是如何工作的

我也将 应用 application 在官方文件的解释得到当前的设备电池电量给予更多的背景下,它是如何工作的

首先使用你喜欢的 IDE 创建一个 Flutter 应用程序

清除 Flutter Starter 应用程序并创建一个新的 dart 文件 home_screen. dart

在 home_screen. dart 内部创建一个新的状态完整的 widget ,返回一个现在的脚本框

import 'package:flutter/material.dart';


class HomeScreen extends StatefulWidget {

  const HomeScreen({Key? key}) : super(key: key);


  

  State<HomeScreen> createState() => _HomeScreenState();

}


class _HomeScreenState extends State<HomeScreen> {

  

  Widget build(BuildContext context) {

    return Scaffold();

  }

}

然后导入那些库

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

请注意,与 Platfrom 的通信是异步的,所以我们将在这个应用程序的未来工作

创建一个字符串

String _batteryLevel = 'Unknown battery level.';

您的代码现在应该如下所示

import 'package:flutter/material.dart';

import 'dart:async';

import 'package:flutter/material.dart';

import 'package:flutter/services.dart';


class HomeScreen extends StatefulWidget {

  const HomeScreen({Key? key}) : super(key: key);


  

  State<HomeScreen> createState() => _HomeScreenState();

}


class _HomeScreenState extends State<HomeScreen> {

  String _batteryLevel = 'Unknown battery level.';


  

  Widget build(BuildContext context) {

    return Scaffold();

  }

}

然后在您的状态内创建一个未来的异步函数 getBatteryLevel

Future<void> _getBatteryLevel() async {

  String batteryLevel;

  try {

    final int result = await platform.invokeMethod('getBatteryLevel');

    batteryLevel = 'Battery level at $result % .';

  } on PlatformException catch (e) {

    batteryLevel = "Failed to get battery level: '${e.message}'.";

  }


  setState(() {

    _batteryLevel = batteryLevel;

  });

}

现在您将注意到平台中的一个错误,这是因为我们还没有定义它

在我们声明它之前,我们需要知道 Method Channel 必须有一个唯一的域,以便两端进行通信,因此它将是不可变的

返回您的状态并释放一个 methodChannel 对象

static const platform = MethodChannel('mediumExplain/battery');

然后,我们需要添加一些简单的用户界面交互,以获得电池电平

用此代码替换生成方法



Widget build(BuildContext context) {

  return Scaffold(

    appBar: AppBar(),

    body: Column(

      children: [

        Text('Your battery level is ${_batteryLevel}'),

        ElevatedButton(

          onPressed: _getBatteryLevel,

          child: const Text('Get Battery Level'),

        ),

      ],

    ),

  );

}

现在是机器人的本机部分,

Android 配置 Kotlin

打开 android 应用程序目录

  • app -> src ->main->kotlin->MainActivity.kt

  • 加上那些进口
import io.flutter.embedding.android.FlutterActivity

import io.flutter.embedding.engine.FlutterEngine

import io.flutter.plugin.common.MethodChannel

import androidx.annotation.NonNull

import android.content.Context

import android.content.ContextWrapper

import android.content.Intent

import android.content.IntentFilter

import android.os.BatteryManager

import android.os.Build.VERSION

import android.os.Build.VERSION_CODES

这些都是本地库从机器人联系电池电平 hteapi

然后添加这个变量,就像我们在 flutter 应用程序中创建的那样

class MainActivity: FlutterActivity() {
  private val CHANNEL = "mediumExplain/battery"

然后重写该函数并保持不变

override fun configureFlutterEngine( flutterEngine: FlutterEngine) {

    super.configureFlutterEngine(flutterEngine)

    MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {

      call, result ->

      // This method is invoked on the main thread.

      // TODO

    }

  }

然后在它添加这个方法,将得到电池百分比和重新发送到我们的通道

  private fun getBatteryLevel(): Int {

    val batteryLevel: Int

    if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {

      val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager

      batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)

    } else {

      val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))

      batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)

    }


    return batteryLevel

  }

注意: 这些和 flutter 没有任何关系这是一个 android 原生 kotlin 代码,你一定不知道,你也可以从 android 或 ios 调用任何 api 即使你不知道原生代码,你可以在 stackoverflow 上搜索,找到任何你需要的相关内容。你只需要在这些代码之间建立一个通道

现在你的整个代码应该看起来像

package com.example.bateery_level


import io.flutter.embedding.android.FlutterActivity

import io.flutter.embedding.engine.FlutterEngine

import io.flutter.plugin.common.MethodChannel

import androidx.annotation.NonNull

import android.content.Context

import android.content.ContextWrapper

import android.content.Intent

import android.content.IntentFilter

import android.os.BatteryManager

import android.os.Build.VERSION

import android.os.Build.VERSION_CODES


class MainActivity: FlutterActivity() {

    private  val CHANNEL ="mediumExplain/battery"


    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {

        super.configureFlutterEngine(flutterEngine)

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {

            // This method is invoked on the main thread.

                call, result ->

            if (call.method == "getBatteryLevel") {

                val batteryLevel = getBatteryLevel()


                if (batteryLevel != -1) {

                    result.success(batteryLevel)

                } else {

                    result.error("UNAVAILABLE", "Battery level not available.", null)

                }

            } else {

                result.notImplemented()

            }

        }


    }

    private fun getBatteryLevel(): Int {

        val batteryLevel: Int

        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {

            val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager

            batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)

        } else {

            val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))

            batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)

        }


        return batteryLevel

    }


}

现在回到你的 flutter 应用程序并运行它

下一步是 ios 配置,如果在 Windows 设备上运行,则跳过

IOS Configuration 配置

在 Xcode 中打开 IOS 文件夹

然后打开运行器目录中的 AppGenerate.swift

在 did FinishLaunchingWithOptions 方法中添加这两行

let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    let batteryChannel = FlutterMethodChannel(name: "mediumExplain/battery",
                                              binaryMessenger: controller.binaryMessenger)

再加上这个

      batteryChannel.setMethodCallHandler({

        (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in


          guard call.method == "getBatteryLevel" else {

            result(FlutterMethodNotImplemented)

            return

          }

          self.receiveBatteryLevel(result: result)

      })

然后在文件的底部添加这个函数

private func receiveBatteryLevel(result: FlutterResult) {

  let device = UIDevice.current

  device.isBatteryMonitoringEnabled = true

  if device.batteryState == UIDevice.BatteryState.unknown {

    result(FlutterError(code: "UNAVAILABLE",

                        message: "Battery level not available.",

                        details: nil))

  } else {

    result(Int(device.batteryLevel * 100))

  }

}

现在你的整个档案应该看看

import UIKit

import Flutter


@UIApplicationMain

@objc class AppDelegate: FlutterAppDelegate {

  override func application(

    _ application: UIApplication,

    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?

  ) -> Bool {

      let controller : FlutterViewController = window?.rootViewController as! FlutterViewController

       let batteryChannel = FlutterMethodChannel(name: "mediumExplain/battery",

                                                 binaryMessenger: controller.binaryMessenger)

      batteryChannel.setMethodCallHandler({

        (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in


          guard call.method == "getBatteryLevel" else {

            result(FlutterMethodNotImplemented)

            return

          }

          self.receiveBatteryLevel(result: result)

      })

    GeneratedPluginRegistrant.register(with: self)

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)

  }

    private func receiveBatteryLevel(result: FlutterResult) {

      let device = UIDevice.current

      device.isBatteryMonitoringEnabled = true

      if device.batteryState == UIDevice.BatteryState.unknown {

        result(FlutterError(code: "UNAVAILABLE",

                            message: "Battery level not available.",

                            details: nil))

      } else {

        result(Int(device.batteryLevel * 100))

      }

    }

}

then run the app from a rea ios device not on a simualtor

GitHub 仓库

Https://github.com/mohaberabi/flutter_method_channel

结束语

如果本文对你有帮助,请转发让更多的朋友阅读。

也许这个操作只要你 3 秒钟,对我来说是一个激励,感谢。

祝你有一个美好的一天~

猫哥课程


© 猫哥

  • 微信 ducafecat

  • https://wiki.ducafecat.tech

  • https://ducafecat.com

Last Updated:
Contributors: ducafecat