在 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