🙃
メソッドチャンネルを使ってみたい!
Flutterからネイティブのコードを呼ぶ
本当にできるのだろうか。。。。
🦜まずは、AppDelegate.swiftに、Flutterから呼ぶコードを書く
ここに書く。x-code開かなくてもできる。
ios/Runner/AppDelegate.swift
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
private var methodChannel: FlutterMethodChannel?
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
// FlutterViewControllerを取得
guard let controller = window?.rootViewController as? FlutterViewController else {
return false
}
// MethodChannelの定義
methodChannel = FlutterMethodChannel(name: "samples.flutter.dev/dateAndTime", binaryMessenger: controller.binaryMessenger)
// MethodChannelのメソッドコールのリスナー設定
methodChannel?.setMethodCallHandler { [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) in
// getDateAndTimeメソッドの実行
if call.method == "getDateAndTime" {
self?.getDateAndTime(result: result)
} else {
result(FlutterMethodNotImplemented)
}
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// 現在の日付と時刻を取得するメソッド
private func getDateAndTime(result: FlutterResult) {
let now = Date()
let formatter = DateFormatter()
formatter.dateStyle = .full
formatter.timeStyle = .medium
let dateTimeString = formatter.string(from: now)
result(dateTimeString)
}
}
🐧Flutter側のコード
メソッドチャンネルを使うコードを書く。今回は今日の曜日と時間を表示するメソッドをSwiftから呼び出す。表示は日本語でされてた!
main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const platform =
const MethodChannel('samples.flutter.dev/dateAndTime');
String _dateAndTime = 'Unknown';
void initState() {
super.initState();
_getDateAndTime();
}
// Swiftのコードのみ
// Future<void> _getDateAndTime() async {
// String dateAndTime;
// try {
// final String result = await platform.invokeMethod('getDateAndTime');
// dateAndTime = 'Date and Time: $result';
// } on PlatformException catch (e) {
// dateAndTime = "Failed to get date and time: '${e.message}'.";
// }
// setState(() {
// _dateAndTime = dateAndTime;
// });
// }
// Androidのコードを追加
Future<void> _getDateAndTime() async {
String dateAndTime;
try {
final String result = await platform.invokeMethod('getDateAndTime');
dateAndTime = 'Date and Time: $result';
} on PlatformException catch (e) {
dateAndTime = "Failed to get date and time: '${e.message}'.";
} on MissingPluginException {
// この例外処理を追加します
dateAndTime =
"Error: MissingPluginException. The functionality might not be available on this platform.";
}
setState(() {
_dateAndTime = dateAndTime;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Demo Home Page'),
),
body: Center(
child: Text(_dateAndTime),
),
);
}
}
実行結果
Androidの場合
こちらにコードを追加。ビルド遅すぎて、確認できてません。すいません🙇♂️
android/app/src/main/kotlin/com/jboy/method_channel_app/MainActivity.kt
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import java.text.SimpleDateFormat
import java.util.*
class MainActivity: FlutterActivity() {
private val CHANNEL = "samples.flutter.dev/dateAndTime"
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
// Note: this method is invoked on the main thread.
call, result ->
if (call.method == "getDateAndTime") {
val dateAndTime = getDateAndTime()
if (dateAndTime != null) {
result.success(dateAndTime)
} else {
result.error("UNAVAILABLE", "Date and Time not available.", null)
}
} else {
result.notImplemented()
}
}
}
private fun getDateAndTime(): String? {
val sdf = SimpleDateFormat("EEEE, MMMM d, yyyy 'at' h:mm a", Locale.US)
return sdf.format(Date())
}
}
まとめ
iOSは早くできるが、Androidがなぜか遅い?
もしかしたら、数十分ぐらいかかるのかも?
こちらが完成品のコード
Androidで使う方法
前回できなかったのは、build.gradleのapplicationIdと一致していないことが問題だったようです。
今回は、端末のストレージの容量を調べるコードをKotlinで作ってみました。
KotlinのコードをFlutterから呼び出す
Androidのネイティブのコードを呼ぶ方法
android/app/src/main/kotlinというKotlinのコードが書かれているフォルダに、
StorageUtil.ktというファイルを作成し、以下のコードを記述する。
このコードは、内部ストレージの情報を取得するコードである。
import android.os.Environment
import android.os.StatFs
object StorageUtil {
fun getInternalStorageInfo(): String {
val statFs = StatFs(Environment.getDataDirectory().path)
val blockSize = statFs.blockSizeLong
val totalBlocks = statFs.blockCountLong
val availableBlocks = statFs.availableBlocksLong
val totalSize = blockSize * totalBlocks
val availableSize = blockSize * availableBlocks
val usedSize = totalSize - availableSize
return "Total: $totalSize, Available: $availableSize, Used: $usedSize"
}
}
MainActivity.ktに以下のコードを追加する。
追加すると、Android端末の内部ストレージの情報がFlutterで表示される。
Flutterがビルドしたときに、MainActivity.ktを見つけるには、package名を合わせる必要がある。
今回だと、com.jboy.android_callというpackage名になっているので、
MainActivity.ktのpackage名もcom.jboy.android_callにする。
package com.jboy.android_call
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/storageInfo"
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "getInternalStorageInfo") {
val storageInfo = StorageUtil.getInternalStorageInfo()
result.success(storageInfo)
} else {
result.notImplemented()
}
}
}
}
成功すると、FlutterでKotlinのコードを呼び出すことができるようになる。
こちらが完成品のソースコード
Discussion