在 Flutter App 中編寫自定義平臺特定程式碼[Method Channel]

語言: CN / TW / HK

在 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 ,返回一個現在的指令碼框

```dart import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {

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

@override

State createState() => _HomeScreenState();

}

class _HomeScreenState extends State {

@override

Widget build(BuildContext context) {

return Scaffold();

}

} ```

然後匯入那些庫

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

請注意,與 Platfrom 的通訊是非同步的,所以我們將在這個應用程式的未來工作

建立一個字串

dart String _batteryLevel = 'Unknown battery level.';

您的程式碼現在應該如下所示

```dart 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);

@override

State createState() => _HomeScreenState();

}

class _HomeScreenState extends State {

String _batteryLevel = 'Unknown battery level.';

@override

Widget build(BuildContext context) {

return Scaffold();

}

} ```

然後在您的狀態內建立一個未來的非同步函式 getBatteryLevel

```dart Future _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 物件

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

然後,我們需要新增一些簡單的使用者介面互動,以獲得電池電平

用此程式碼替換生成方法

```dart @override

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

  • 加上那些進口

```java 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 應用程式中建立的那樣

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

然後重寫該函式並保持不變

```dart override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {

super.configureFlutterEngine(flutterEngine)

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

  call, result ->

  // This method is invoked on the main thread.

  // TODO

}

} ```

然後在它新增這個方法,將得到電池百分比和重新發送到我們的通道

```dart 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 上搜索,找到任何你需要的相關內容。你只需要在這些程式碼之間建立一個通道

現在你的整個程式碼應該看起來像

```java 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 方法中新增這兩行

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

再加上這個

```swift batteryChannel.setMethodCallHandler({

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


      guard call.method == "getBatteryLevel" else {

        result(FlutterMethodNotImplemented)

        return

      }

      self.receiveBatteryLevel(result: result)

  })

```

然後在檔案的底部新增這個函式

```swift 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))

}

} ```

現在你的整個檔案應該看看

```swift 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://video.ducafecat.tech