カスタム プラットフォーム固有のコードの作成
このガイドでは、プラットフォーム固有のカスタム コードを作成する方法について説明します。 いくつかのプラットフォーム固有の機能が利用可能です 既存のパッケージを通じて。 見るパッケージの使用。
Flutter は柔軟なシステムを使用しており、 直接動作する言語によるプラットフォーム固有の API これらの API を使用すると:
- Android 上の Kotlin または Java
- iOS 上の Swift または Objective-C
- Windows 上の C++
- macOS 上の Objective-C
- Linux 上の C
Flutter の組み込みプラットフォーム固有 API サポート コード生成に依存せず、 むしろ、柔軟なメッセージ受け渡しスタイルを重視しています。 あるいは、鳩のパッケージ構造化されたタイプセーフメッセージの送信コード生成を使用すると:
-
アプリの Flutter 部分はメッセージをそのホスト、 プラットフォーム チャネル経由でのアプリの非 Dart 部分。
-
のホストプラットフォーム チャネルをリッスンし、メッセージを受信します。 次に、次を使用して、任意の数のプラットフォーム固有の API を呼び出します。 ネイティブ プログラミング言語 — そして応答をクライアント、アプリの Flutter 部分。
アーキテクチャの概要: プラットフォーム チャネル
メッセージはクライアント (UI) 間で受け渡されます。 プラットフォームを使用するホスト (プラットフォーム) この図に示すように、チャネルは次のようになります。
メッセージと応答は非同期で渡されます。 ユーザー インターフェイスの応答性を維持するため。
クライアント側では、MethodChannel
送信を有効にする
メソッド呼び出しに対応するメッセージ。ホーム側には、MethodChannel
Android の場合 (MethodChannelAndroid
) とFlutterMethodChannel
iOS の場合 (MethodChanneliOS
)
メソッド呼び出しの受信と送信を可能にする
結果。これらのクラスを使用すると、プラットフォーム プラグインを開発できます。
「定型コード」はほとんどありません。
プラットフォーム チャネルのデータ型のサポートとコーデック
標準プラットフォーム チャネルは、サポートする標準メッセージ コーデックを使用します。
ブール値などの単純な JSON のような値の効率的なバイナリ シリアル化。
数値、文字列、バイトバッファ、およびこれらのリストとマップ
(見るStandardMessageCodec
詳細については)。
これらの値のシリアル化とシリアル化解除
値を送受信すると、メッセージが自動的に生成されます。
次の表は、Dart 値がどのように受信されるかを示しています。 プラットフォーム側とその逆:
ダーツ | ジャワ |
---|---|
ヌル | ヌル |
ブール | java.lang.Boolean |
整数 | java.lang.Integer |
int (32 ビットでは不十分な場合) | java.lang.Long |
ダブル | java.lang.Double |
弦 | java.lang.String |
Uint8List | バイト[] |
Int32List | int[] |
Int64List | 長さ[] |
Float32List | 浮く[] |
Float64List | ダブル[] |
リスト | java.util.ArrayList |
地図 | java.util.HashMap |
ダーツ | コトリン |
---|---|
ヌル | ヌル |
ブール | ブール値 |
整数 | 内部 |
int (32 ビットでは不十分な場合) | 長さ |
ダブル | ダブル |
弦 | 弦 |
Uint8List | バイト配列 |
Int32List | IntArray |
Int64List | 長い配列 |
Float32List | 浮動小数点配列 |
Float64List | ダブルアレイ |
リスト | リスト |
地図 | ハッシュマップ |
ダーツ | 目的-C |
---|---|
ヌル | nil (ネストされている場合は NSNull) |
ブール | NSNumbernumberWithBool: |
整数 | NSNumbernumberWithInt: |
int (32 ビットでは不十分な場合) | NSNumbernumberWithLong: |
ダブル | NSNumbernumberWithDouble: |
弦 | NS文字列 |
Uint8List | FlutterStandardTypedData 型付きDataWithBytes: |
Int32List | FlutterStandardTypedData 型付きDataWithInt32: |
Int64List | FlutterStandardTypedData 型付きDataWithInt64: |
Float32List | FlutterStandardTypedData 型付きDataWithFloat32: |
Float64List | FlutterStandardTypedData 型付きDataWithFloat64: |
リスト | NSArray |
地図 | NSDictionary |
ダーツ | 迅速 |
---|---|
ヌル | なし |
ブール | NSNumber(値: ブール値) |
整数 | NSNumber(値: Int32) |
int (32 ビットでは不十分な場合) | NSNumber(値: Int) |
ダブル | NSNumber(値: Double) |
弦 | 弦 |
Uint8List | FlutterStandardTypedData(バイト: データ) |
Int32List | FlutterStandardTypedData(int32: データ) |
Int64List | FlutterStandardTypedData(int64: データ) |
Float32List | FlutterStandardTypedData(float32:データ) |
Float64List | FlutterStandardTypedData(float64:データ) |
リスト | 配列 |
地図 | 辞書 |
ダーツ | C++ |
---|---|
ヌル | EncodableValue() |
ブール | EncodableValue(ブール値) |
整数 | EncodableValue(int32_t) |
int (32 ビットでは不十分な場合) | EncodableValue(int64_t) |
ダブル | EncodableValue(double) |
弦 | EncodableValue(std::string) |
Uint8List | EncodableValue(std::vector |
Int32List | EncodableValue(std::vector |
Int64List | EncodableValue(std::vector |
Float32List | EncodableValue(std::vector |
Float64List | EncodableValue(std::vector |
リスト | EncodableValue(std::vector |
地図 | EncodableValue(std::map<EncodableValue, EncodableValue>) |
ダーツ | C (Gオブジェクト) |
---|---|
ヌル | FlValue() |
ブール | FlValue(ブール値) |
整数 | FlValue(int64_t) |
ダブル | FlValue(倍精度) |
弦 | FlValue(gchar*) |
Uint8List | FlValue(uint8_t*) |
Int32List | FlValue(int32_t*) |
Int64List | FlValue(int64_t*) |
Float32List | FlValue(float*) |
Float64List | FlValue(double*) |
リスト | Fl値(Fl値) |
地図 | FlValue(FlValue, FlValue) |
例: プラットフォーム チャネルを使用したプラットフォーム固有のコードの呼び出し
次のコードは、呼び出し方法を示しています。
取得および表示するプラットフォーム固有の API
現在のバッテリーレベル。それは使用しています
アンドロイドBatteryManager
API、
iOSdevice.batteryLevel
API、
窓GetSystemPowerStatus
API、
そしてリナックスUPower
単一の API
プラットフォームメッセージ、getBatteryLevel()
。
この例では、プラットフォーム固有のコードを内部に追加します。 メインアプリ自体。再利用したい場合は、 複数のアプリ用のプラットフォーム固有のコード、 プロジェクトの作成手順が若干異なります (見るパッケージの開発)、 ただし、プラットフォームのチャネルコード 今でも同じように書かれています。
ステップ 1: 新しいアプリ プロジェクトを作成する
新しいアプリを作成することから始めます。
- ターミナルで次を実行します。
flutter create batterylevel
デフォルトでは、テンプレートは Kotlin を使用した Android コードの作成をサポートしています。
または Swift を使用した iOS コード。 Java または Objective-C を使用するには、
使用-i
および/または-a
フラグ:
- ターミナルで次を実行します。
flutter create -i objc -a java batterylevel
ステップ 2: Flutter プラットフォーム クライアントを作成する
アプリのState
クラスは現在のアプリの状態を保持します。
それを拡張して現在のバッテリー状態を保持します。
まず、チャネルを構築します。使うMethodChannel
単一の
バッテリーレベルを返すプラットフォームメソッド。
チャネルのクライアント側とホスト側は、
チャネルコンストラクターで渡されるチャネル名。
1 つのアプリで使用されるすべてのチャンネル名は、
一意であること;チャンネル名の前に一意の「ドメイン」を付けます
プレフィックス」、例:samples.flutter.dev/battery
。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class _MyHomePageState extends State<MyHomePage> {
static const platform = MethodChannel('samples.flutter.dev/battery');
// Get battery level.
次に、メソッド チャネルでメソッドを呼び出します。
を使用して呼び出す具体的なメソッドを指定する
のString
識別子getBatteryLevel
。
呼び出しは失敗する可能性があります。たとえば、
プラットフォームがサポートしていない場合は、
プラットフォーム API (シミュレーターで実行する場合など)、
それでラップしますinvokeMethod
try-catch ステートメントで呼び出します。
返された結果を使用して、ユーザー インターフェイスの状態を更新します。_batteryLevel
中身setState
。
// Get battery level.
String _batteryLevel = 'Unknown battery level.';
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;
});
}
最後に、build
テンプレートからメソッドへ
バッテリーを表示する小さなユーザーインターフェイスが含まれています
文字列内の状態と、値を更新するためのボタン。
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _getBatteryLevel,
child: const Text('Get Battery Level'),
),
Text(_batteryLevel),
],
),
),
);
}
ステップ 3: Android プラットフォーム固有の実装を追加する
まず、Flutter アプリの Android ホスト部分を開きます Android Studio の場合:
-
Android Studioを起動する
-
メニュー項目を選択しますファイル > 開く…
-
Flutter アプリが保存されているディレクトリに移動します。 そして、アンドロイドその中にあるフォルダー。クリックOK。
-
ファイルを開く
MainActivity.kt
にありますコトリン内のフォルダー プロジェクトビュー。
内部configureFlutterEngine()
メソッドを作成するMethodChannel
そして電話するsetMethodCallHandler()
。必ず同じチャンネル名を使用してください。
Flutterクライアント側で使用されました。
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity: FlutterActivity() {
private val CHANNEL = "samples.flutter.dev/battery"
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
}
}
}
Android バッテリー API を使用する Android Kotlin コードを追加します。 バッテリーレベルを取得します。このコードはあなたとまったく同じです ネイティブ Android アプリに書き込むことになります。
まず、必要なインポートをファイルの先頭に追加します。
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
次に、次のメソッドをMainActivity
クラス、
の下にconfigureFlutterEngine()
方法:
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
}
最後に、setMethodCallHandler()
先ほど追加したメソッド。
単一プラットフォームのメソッドを処理する必要があります。getBatteryLevel()
、
それでそれをテストしてくださいcall
口論。
このプラットフォーム メソッドの実装では、
前のステップで記述された Android コード。両方の応答を返します。
を使用した成功とエラーのケースresult
口論。
不明なメソッドが呼び出された場合は、代わりにそれを報告します。
次のコードを削除します。
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
// This method is invoked on the main thread.
// TODO
}
そして、次のように置き換えます。
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()
}
}
まず、Flutter アプリの Android ホスト部分を開きます Android Studio の場合:
-
Android Studioを起動する
-
メニュー項目を選択しますファイル > 開く…
-
Flutter アプリが保存されているディレクトリに移動します。 そして、アンドロイドその中にあるフォルダー。クリックOK。
-
を開きます
MainActivity.java
ファイルは次の場所にありますジャワ内のフォルダー プロジェクトビュー。
次に、MethodChannel
そして、MethodCallHandler
の中でconfigureFlutterEngine()
方法。
必ず、使用したものと同じチャンネル名を使用してください。
クライアント側を flutterします。
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "samples.flutter.dev/battery";
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
// This method is invoked on the main thread.
// TODO
}
);
}
}
Android バッテリー API を使用する Android Java コードを次の場所に追加します。 バッテリーレベルを取得します。このコードはあなたとまったく同じです ネイティブ Android アプリに書き込むことになります。
まず、必要なインポートをファイルの先頭に追加します。
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;
import android.os.Bundle;
次に、アクティビティ クラスに新しいメソッドとして次のコードを追加します。
の下にconfigureFlutterEngine()
方法:
private int getBatteryLevel() {
int batteryLevel = -1;
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
} else {
Intent intent = new ContextWrapper(getApplicationContext()).
registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
}
return batteryLevel;
}
最後に、setMethodCallHandler()
先ほど追加したメソッド。
単一プラットフォームのメソッドを処理する必要があります。getBatteryLevel()
、
それでそれをテストしてくださいcall
口論。の実装
このプラットフォーム メソッドは、記述された Android コードを呼び出します。
前のステップで、両方の応答を返します。
を使用した成功とエラーのケースresult
口論。
不明なメソッドが呼び出された場合は、代わりにそれを報告します。
次のコードを削除します。
(call, result) -> {
// This method is invoked on the main thread.
// TODO
}
そして、次のように置き換えます。
(call, result) -> {
// This method is invoked on the main thread.
if (call.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success(batteryLevel);
} else {
result.error("UNAVAILABLE", "Battery level not available.", null);
}
} else {
result.notImplemented();
}
}
これで、Android でアプリを実行できるようになります。 Androidをご利用の場合 エミュレータ、拡張コントロールパネルでバッテリーレベルを設定します からアクセス可能…ツールバーのボタン。
ステップ 4: iOS プラットフォーム固有の実装を追加する
まず、Xcode で Flutter アプリの iOS ホスト部分を開きます。
-
Xcodeを起動します。
-
メニュー項目を選択しますファイル > 開く…。
-
Flutter アプリが保存されているディレクトリに移動し、iosその中にあるフォルダー。クリックOK。
Objective-C を使用する標準テンプレート セットアップに Swift のサポートを追加します。
-
「ランナー」>「ランナー」を展開しますプロジェクトナビゲーターで。
-
ファイルを開く
AppDelegate.swift
以下にありますランナー > ランナープロジェクトナビゲーターで。
オーバーライドapplication:didFinishLaunchingWithOptions:
機能し、創造する
あるFlutterMethodChannel
チャンネル名に紐づくsamples.flutter.dev/battery
:
@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: "samples.flutter.dev/battery",
binaryMessenger: controller.binaryMessenger)
batteryChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
// This method is invoked on the UI thread.
// Handle battery messages.
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
次に、iOS バッテリー API を使用して取得する iOS Swift コードを追加します。 バッテリーレベル。このコードはあなたとまったく同じです ネイティブ iOS アプリに書き込むことになります。
以下を新しいメソッドとして下部に追加します。AppDelegate.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))
}
}
最後に、setMethodCallHandler()
先ほど追加したメソッド。
単一プラットフォームのメソッドを処理する必要があります。getBatteryLevel()
、
それでそれをテストしてくださいcall
口論。
このプラットフォーム メソッドの実装では、
前の手順で作成した iOS コード。未知の方法の場合
が呼び出された場合は、代わりにそれを報告します。
batteryChannel.setMethodCallHandler({
[weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
// This method is invoked on the UI thread.
guard call.method == "getBatteryLevel" else {
result(FlutterMethodNotImplemented)
return
}
self?.receiveBatteryLevel(result: result)
})
まず、Xcode で Flutter アプリの iOS ホスト部分を開きます。
-
Xcodeを起動します。
-
メニュー項目を選択しますファイル > 開く…。
-
Flutter アプリが保存されているディレクトリに移動します。 そして、iosその中にあるフォルダー。クリックOK。
-
Xcode プロジェクトがエラーなしでビルドされることを確認してください。
-
ファイルを開く
AppDelegate.m
、以下にありますランナー > ランナープロジェクトナビゲーターで。
を作成しますFlutterMethodChannel
内にハンドラーを追加しますapplication
didFinishLaunchingWithOptions:
方法。
必ず同じチャンネル名を使用してください
Flutter クライアント側で使用されていたものと同じです。
#import <Flutter/Flutter.h>
#import "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
FlutterMethodChannel* batteryChannel = [FlutterMethodChannel
methodChannelWithName:@"samples.flutter.dev/battery"
binaryMessenger:controller.binaryMessenger];
[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
// This method is invoked on the UI thread.
// TODO
}];
[GeneratedPluginRegistrant registerWithRegistry:self];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
次に、iOS バッテリー API を使用する iOS ObjectiveC コードを追加します。 バッテリーレベルを取得します。このコードはあなたとまったく同じです ネイティブ iOS アプリに書き込むことになります。
に次のメソッドを追加しますAppDelegate
授業、直前@end
:
- (int)getBatteryLevel {
UIDevice* device = UIDevice.currentDevice;
device.batteryMonitoringEnabled = YES;
if (device.batteryState == UIDeviceBatteryStateUnknown) {
return -1;
} else {
return (int)(device.batteryLevel * 100);
}
}
最後に、setMethodCallHandler()
先ほど追加したメソッド。
単一プラットフォームのメソッドを処理する必要があります。getBatteryLevel()
、
それでそれをテストしてくださいcall
口論。の実装
このプラットフォーム メソッドは、前の手順で作成した iOS コードを呼び出します。
そして、成功とエラーの両方の場合に応答を返します。
のresult
口論。不明なメソッドが呼び出された場合は、代わりにそれを報告します。
__weak typeof(self) weakSelf = self;
[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
// This method is invoked on the UI thread.
if ([@"getBatteryLevel" isEqualToString:call.method]) {
int batteryLevel = [weakSelf getBatteryLevel];
if (batteryLevel == -1) {
result([FlutterError errorWithCode:@"UNAVAILABLE"
message:@"Battery level not available."
details:nil]);
} else {
result(@(batteryLevel));
}
} else {
result(FlutterMethodNotImplemented);
}
}];
これで、iOS でアプリを実行できるようになります。 iOSシミュレータを使用する場合は、 バッテリーAPIをサポートしていないことに注意してください。 アプリには「バッテリー残量が利用できません」と表示されます。
ステップ 5: Windows プラットフォーム固有の実装を追加する
まず、Visual Studio で Flutter アプリの Windows ホスト部分を開きます。
-
走る
flutter build windows
プロジェクトディレクトリに一度追加して生成します Visual Studio ソリューション ファイル。 -
Visual Studio を起動します。
-
選択するプロジェクトまたはソリューションを開く。
-
Flutter アプリが保存されているディレクトリに移動し、建てるフォルダー、次にウィンドウズフォルダーを選択し、
batterylevel.sln
ファイル。 クリック開ける。
プラットフォーム チャネル メソッドの C++ 実装を追加します。
-
拡大バッテリーレベル > ソースファイルソリューション エクスプローラーで。
-
ファイルを開く
flutter_window.cpp
。
まず、必要なインクルードをファイルの先頭に追加します。
後#include "flutter_window.h"
:
#include <flutter/event_channel.h>
#include <flutter/event_sink.h>
#include <flutter/event_stream_handler_functions.h>
#include <flutter/method_channel.h>
#include <flutter/standard_method_codec.h>
#include <windows.h>
#include <memory>
を編集しますFlutterWindow::OnCreate
メソッドと作成
あるflutter::MethodChannel
チャンネル名に紐づくsamples.flutter.dev/battery
:
bool FlutterWindow::OnCreate() {
// ...
RegisterPlugins(flutter_controller_->engine());
flutter::MethodChannel<> channel(
flutter_controller_->engine()->messenger(), "samples.flutter.dev/battery",
&flutter::StandardMethodCodec::GetInstance());
channel.SetMethodCallHandler(
[](const flutter::MethodCall<>& call,
std::unique_ptr<flutter::MethodResult<>> result) {
// TODO
});
SetChildContent(flutter_controller_->view()->GetNativeWindow());
return true;
}
次に、Windows バッテリー API を使用する C++ コードを追加します。 バッテリーレベルを取得します。このコードは次とまったく同じです ネイティブ Windows アプリケーションで記述することになります。
以下を新しい関数として先頭に追加しますflutter_window.cpp
の直後#include
セクション:
static int GetBatteryLevel() {
SYSTEM_POWER_STATUS status;
if (GetSystemPowerStatus(&status) == 0 || status.BatteryLifePercent == 255) {
return -1;
}
return status.BatteryLifePercent;
}
最後に、setMethodCallHandler()
先ほど追加したメソッド。
単一プラットフォームのメソッドを処理する必要があります。getBatteryLevel()
、
それでそれをテストしてくださいcall
口論。
このプラットフォーム メソッドの実装では、
前の手順で記述した Windows コード。未知の方法の場合
が呼び出された場合は、代わりにそれを報告します。
次のコードを削除します。
channel.SetMethodCallHandler(
[](const flutter::MethodCall<>& call,
std::unique_ptr<flutter::MethodResult<>> result) {
// TODO
});
そして、次のように置き換えます。
channel.SetMethodCallHandler(
[](const flutter::MethodCall<>& call,
std::unique_ptr<flutter::MethodResult<>> result) {
if (call.method_name() == "getBatteryLevel") {
int battery_level = GetBatteryLevel();
if (battery_level != -1) {
result->Success(battery_level);
} else {
result->Error("UNAVAILABLE", "Battery level not available.");
}
} else {
result->NotImplemented();
}
});
これで、Windows 上でアプリケーションを実行できるようになります。 デバイスにバッテリーがない場合は、 「バッテリー残量が利用できません」と表示されます。
ステップ 6: macOS プラットフォーム固有の実装を追加する
まず、Xcode で Flutter アプリの macOS ホスト部分を開きます。
-
Xcodeを起動します。
-
メニュー項目を選択しますファイル > 開く…。
-
Flutter アプリが保存されているディレクトリに移動し、マックOSその中にあるフォルダー。クリックOK。
プラットフォーム チャネル メソッドの Swift 実装を追加します。
-
「ランナー」>「ランナー」を展開しますプロジェクトナビゲーターで。
-
ファイルを開く
MainFlutterWindow.swift
以下にありますランナー > ランナープロジェクトナビゲーターで。
まず、必要なインポートをファイルの先頭、直後に追加します。import FlutterMacOS
:
import IOKit.ps
を作成しますFlutterMethodChannel
チャンネル名に紐づくsamples.flutter.dev/battery
の中にawakeFromNib
方法:
override func awakeFromNib() {
// ...
self.setFrame(windowFrame, display: true)
let batteryChannel = FlutterMethodChannel(
name: "samples.flutter.dev/battery",
binaryMessenger: flutterViewController.engine.binaryMessenger)
batteryChannel.setMethodCallHandler { (call, result) in
// This method is invoked on the UI thread.
// Handle battery messages.
}
RegisterGeneratedPlugins(registry: flutterViewController)
super.awakeFromNib()
}
}
次に、IOKit バッテリー API を使用して情報を取得する macOS Swift コードを追加します。 バッテリーレベル。このコードはあなたとまったく同じです ネイティブ macOS アプリで記述することになります。
以下を新しいメソッドとして下部に追加します。MainFlutterWindow.swift
:
private func getBatteryLevel() -> Int? {
let info = IOPSCopyPowerSourcesInfo().takeRetainedValue()
let sources: Array<CFTypeRef> = IOPSCopyPowerSourcesList(info).takeRetainedValue() as Array
if let source = sources.first {
let description =
IOPSGetPowerSourceDescription(info, source).takeUnretainedValue() as! [String: AnyObject]
if let level = description[kIOPSCurrentCapacityKey] as? Int {
return level
}
}
return nil
}
最後に、setMethodCallHandler
先ほど追加したメソッド。
単一プラットフォームのメソッドを処理する必要があります。getBatteryLevel()
、
それでそれをテストしてくださいcall
口論。
このプラットフォーム メソッドの実装では、
前の手順で作成した macOS コード。未知の方法の場合
が呼び出された場合は、代わりにそれを報告します。
batteryChannel.setMethodCallHandler { (call, result) in
switch call.method {
case "getBatteryLevel":
guard let level = getBatteryLevel() else {
result(
FlutterError(
code: "UNAVAILABLE",
message: "Battery level not available",
details: nil))
return
}
result(level)
default:
result(FlutterMethodNotImplemented)
}
}
これで、macOS 上でアプリケーションを実行できるようになります。 デバイスにバッテリーがない場合は、 「バッテリー残量が利用できません」と表示されます。
ステップ 7: Linux プラットフォーム固有の実装を追加する
この例では、upower
開発者のヘッダー。
これはおそらくディストリビューションから入手できます。たとえば、次のとおりです。
sudo apt install libupower-glib-dev
まず、エディターで Flutter アプリの Linux ホスト部分を開きます。 お好みの。以下の手順は、Visual Studio Code を使用したものです。 「C/C++」および「CMake」拡張機能がインストールされていますが、他の IDE 用に調整できます。
-
Visual Studio コードを起動します。
-
を開きますリナックスプロジェクト内のディレクトリ。
-
選ぶはいプロンプトで次のように尋ねます。
Would you like to configure project "linux"?
。 これにより、C++ オートコンプリートが有効になります。 -
ファイルを開く
my_application.cc
。
まず、必要なインクルードをファイルの先頭に追加します。
後#include <flutter_linux/flutter_linux.h
:
#include <math.h>
#include <upower.h>
を追加FlMethodChannel
に_MyApplication
構造体:
struct _MyApplication {
GtkApplication parent_instance;
char** dart_entrypoint_arguments;
FlMethodChannel* battery_channel;
};
必ず掃除してくださいmy_application_dispose
:
static void my_application_dispose(GObject* object) {
MyApplication* self = MY_APPLICATION(object);
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
g_clear_object(&self->battery_channel);
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
}
を編集しますmy_application_activate
メソッドと初期化battery_channel
チャンネル名を使ってsamples.flutter.dev/battery
に電話をかけた直後fl_register_plugins
:
static void my_application_activate(GApplication* application) {
// ...
fl_register_plugins(FL_PLUGIN_REGISTRY(self->view));
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
self->battery_channel = fl_method_channel_new(
fl_engine_get_binary_messenger(fl_view_get_engine(view)),
"samples.flutter.dev/battery", FL_METHOD_CODEC(codec));
fl_method_channel_set_method_call_handler(
self->battery_channel, battery_method_call_handler, self, nullptr);
gtk_widget_grab_focus(GTK_WIDGET(self->view));
}
次に、Linux バッテリー API を使用する C コードを追加します。 バッテリーレベルを取得します。このコードは次とまったく同じです ネイティブ Linux アプリケーションで記述することになります。
以下を新しい関数として先頭に追加しますmy_application.cc
の直後G_DEFINE_TYPE
ライン:
static FlMethodResponse* get_battery_level() {
// Find the first available battery and report that.
g_autoptr(UpClient) up_client = up_client_new();
g_autoptr(GPtrArray) devices = up_client_get_devices2(up_client);
if (devices->len == 0) {
return FL_METHOD_RESPONSE(fl_method_error_response_new(
"UNAVAILABLE", "Device does not have a battery.", nullptr));
}
UpDevice* device = (UpDevice*)(g_ptr_array_index(devices, 0));
double percentage = 0;
g_object_get(device, "percentage", &percentage, nullptr);
g_autoptr(FlValue) result =
fl_value_new_int(static_cast<int64_t>(round(percentage)));
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
}
最後に、battery_method_call_handler
参照される関数
以前の電話でfl_method_channel_set_method_call_handler
。
単一プラットフォームのメソッドを処理する必要があります。getBatteryLevel
、
それでそれをテストしてくださいmethod_call
口論。
この関数呼び出しの実装は、
前の手順で作成した Linux コード。未知の方法の場合
が呼び出された場合は、代わりにそれを報告します。
の後に次のコードを追加しますget_battery_level
関数:
static void battery_method_call_handler(FlMethodChannel* channel,
FlMethodCall* method_call,
gpointer user_data) {
g_autoptr(FlMethodResponse) response = nullptr;
if (strcmp(fl_method_call_get_name(method_call), "getBatteryLevel") == 0) {
response = get_battery_level();
} else {
response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
}
g_autoptr(GError) error = nullptr;
if (!fl_method_call_respond(method_call, response, &error)) {
g_warning("Failed to send response: %s", error->message);
}
}
これで、Linux 上でアプリケーションを実行できるようになります。 デバイスにバッテリーがない場合は、 「バッテリーレベルが利用できません」と表示されます。
Pigeon を使用したタイプセーフ プラットフォーム チャネル
前の例では、MethodChannel
ホストとクライアントの間で通信するため、
これはタイプセーフではありません。通話と受信
メッセージはホストとクライアントの宣言に依存します
メッセージが機能するためには、同じ引数とデータ型が必要です。
使用できます鳩としてパッケージ化する
の代替品MethodChannel
でメッセージを送信するコードを生成するには
構造化されたタイプセーフな方法。
と鳩、メッセージングプロトコルが定義されています
Dart のサブセット内でメッセージングを生成する
Android または iOS 用のコード。より完全なものを見つけることができます
例と詳細情報pigeon
pub.dev のページ。
使用する鳩一致させる必要がなくなります ホストとクライアント間の文字列 メッセージの名前とデータ型については。 サポートするもの: ネストされたクラス、グループ化 API へのメッセージ、生成 非同期ラッパーコードとメッセージの送信 どちらの方向でも。生成されたコードは読み取り可能です 間に矛盾がないことを保証します 異なるバージョンの複数のクライアント。 サポートされている言語は、Objective-C、Java、Kotlin、 および Swift (Objective-C 相互運用機能付き)。
ハトの例
鳩ファイル:
import 'package:pigeon/pigeon.dart';
class SearchRequest {
final String query;
SearchRequest({required this.query});
}
class SearchReply {
final String result;
SearchReply({required this.result});
}
@HostApi()
abstract class Api {
@async
SearchReply search(SearchRequest request);
}
ダーツの使用法:
import 'generated_pigeon.dart';
Future<void> onClick() async {
SearchRequest request = SearchRequest(query: 'test');
Api api = SomeApi();
SearchReply reply = await api.search(request);
print('reply: ${reply.result}');
}
プラットフォーム固有のコードを UI コードから分離する
プラットフォーム固有のコードを使用する予定がある場合 複数の Flutter アプリでは、次のことを検討してください。 コードをプラットフォーム プラグインに分割する メインアプリケーションの外側のディレクトリにあります。 見るパッケージの開発詳細については。
プラットフォーム固有のコードをパッケージとして公開する
プラットフォーム固有のコードを他の開発者と共有するには Flutter エコシステムについては、を参照してください。パッケージの公開。
カスタムチャンネルとコーデック
上記以外にもd1be9d7e-efd2-4b92-aa95-8ccf3a7e08da、
より基本的なものを使用することもできますBasicMessageChannel
基本をサポートする、
カスタム メッセージ コーデックを使用した非同期メッセージ パッシング。
専門的なものを使用することもできますBinaryCodec
、StringCodec
、 とJSONMessageCodec
クラスを使用するか、独自のコーデックを作成します。
カスタム コーデックの例も確認してください。
の中にcloud_firestore
プラグイン、
さらに多くのものをシリアル化および逆シリアル化できます
デフォルトのタイプよりもタイプが異なります。
チャネルとプラットフォームのスレッド化
Flutter 向けのプラットフォーム側のチャネルを呼び出す場合、
プラットフォームのメインスレッドで呼び出します。
Flutter でプラットフォーム側向けのチャネルを呼び出す場合、
どれからでも呼び出しますIsolate
それが根ですIsolate
、また背景として登録されているものIsolate
。
プラットフォーム側のハンドラーはプラットフォームのメインスレッドで実行できます。
タスク キューを使用する場合は、バックグラウンド スレッドで実行することもできます。
プラットフォーム側のハンドラーを非同期的に呼び出すことができます
そしてどのスレッドでも。
バックグラウンド分離からのプラグインとチャンネルの使用
プラグインとチャンネルは誰でも使用できますIsolate
、 でもあのIsolate
である必要があります
根Isolate
(Flutterで作成したもの)または背景として登録したものIsolate
根のためにIsolate
。
次の例は、背景を登録する方法を示しています。Isolate
そうするには
バックグラウンドからプラグインを使用するIsolate
。
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
void _isolateMain(RootIsolateToken rootIsolateToken) async {
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
print(sharedPreferences.getBool('isDebug'));
}
void main() {
RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;
Isolate.spawn(_isolateMain, rootIsolateToken);
}
バックグラウンドスレッドでのチャネルハンドラーの実行
チャネルのプラットフォーム側ハンドラーが バックグラウンド スレッドで実行する場合は、 タスクキューAPI。現在、この機能は iOS と Android でサポートされています。
Javaの場合:
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
BinaryMessenger messenger = binding.getBinaryMessenger();
BinaryMessenger.TaskQueue taskQueue =
messenger.makeBackgroundTaskQueue();
channel =
new MethodChannel(
messenger,
"com.example.foo",
StandardMethodCodec.INSTANCE,
taskQueue);
channel.setMethodCallHandler(this);
}
Kotlin の場合:
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
val taskQueue =
flutterPluginBinding.binaryMessenger.makeBackgroundTaskQueue()
channel = MethodChannel(flutterPluginBinding.binaryMessenger,
"com.example.foo",
StandardMethodCodec.INSTANCE,
taskQueue)
channel.setMethodCallHandler(this)
}
スウィフトの場合:
public static func register(with registrar: FlutterPluginRegistrar) {
let taskQueue = registrar.messenger.makeBackgroundTaskQueue()
let channel = FlutterMethodChannel(name: "com.example.foo",
binaryMessenger: registrar.messenger(),
codec: FlutterStandardMethodCodec.sharedInstance,
taskQueue: taskQueue)
let instance = MyPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
Objective-C の場合:
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
NSObject<FlutterTaskQueue>* taskQueue =
[[registrar messenger] makeBackgroundTaskQueue];
FlutterMethodChannel* channel =
[FlutterMethodChannel methodChannelWithName:@"com.example.foo"
binaryMessenger:[registrar messenger]
codec:[FlutterStandardMethodCodec sharedInstance]
taskQueue:taskQueue];
MyPlugin* instance = [[MyPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
Android の UI スレッドにジャンプする
チャネルの UI スレッド要件に準拠するには、
バックグラウンド スレッドからジャンプする必要がある場合があります
Android の UI スレッドに接続してチャネル メソッドを実行します。
Android では、次のようにしてこれを実現できます。post()
しているRunnable
Android の UI スレッドへLooper
、
それが原因となるRunnable
で実行する
メインスレッドは次の機会に。
Javaの場合:
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// Call the desired channel message here.
}
});
Kotlin の場合:
Handler(Looper.getMainLooper()).post {
// Call the desired channel message here.
}
iOS のメインスレッドにジャンプする
チャネルのメインスレッド要件に準拠するには、 バックグラウンド スレッドからジャンプする必要がある場合があります。 チャネルメソッドを実行するiOSのメインスレッド。 iOS でこれを実行するには、ブロックメインでディスパッチキュー:
Objective-C の場合:
dispatch_async(dispatch_get_main_queue(), ^{
// Call the desired channel message here.
});
スウィフトの場合:
DispatchQueue.main.async {
// Call the desired channel message here.
}