📲

ネイティブiOSの機能をブリッジするFlutter plugin作成手順

2023/10/26に公開

先日screen_time_api_iosというpackageをリリースしたので、その手順を記事に記します。

https://pub.dev/packages/screen_time_api_ios

ほとんどの手順はFlutterのパッケージ作成から公開までやってみた|ギャップロという記事を参考にしました🙏

本記事では、pluginだけに焦点を当て、自分の体験も付け加えたいと思います。

プロジェクト作成

Android Studioでやる場合は、以下のようにNewProject作成の時に、ProjectTypeをPluginに指定します。(Flutterのフレームワークのみを使うpackageはPackageを選択し、今回のようにSwiftやKotlinなどのネイティブフレームワークを使う場合はPluginです)

また、コマンドラインでプロジェクト作成する場合は、今回の場合は以下でした。iosのみ対応です。

flutter create --template=plugin --platforms=ios plugin_demo

(plugin_demoがplugin名です)

参考↓
https://docs.flutter.dev/packages-and-plugins/developing-packages

実装

自動でexampleフォルダができますので、exampleのmain.dartから呼び出す形で動作するように、pluginの方を作っていきます。

plugin_demoという名前でpluginを作った場合は、以下のようにlibの中にデフォルトで3つのファイルが作成されます。

一番上のplugin_demo.dartがpluginとしてexampleの側から呼ばれるクラスになります。なので、ここに呼び出したい関数を作っていく形になります。以下はデフォルトの状態です。

plugin_demo.dart
import 'plugin_demo_platform_interface.dart';

class PluginDemo {
  Future<String?> getPlatformVersion() {
    return PluginDemoPlatform.instance.getPlatformVersion();
  }
}

また、plugin_demo_method_channel.dartというファイルで、MethodChannelの呼び出しを行います。以下はデフォルトの状態です。

plugin_demo_method_channel.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'plugin_demo_platform_interface.dart';

class MethodChannelPluginDemo extends PluginDemoPlatform {
  
  final methodChannel = const MethodChannel('plugin_demo');

  
  Future<String?> getPlatformVersion() async {
    final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
    return version;
  }
}

で、methodChannelの関数のswiftのコードはPluginDemoPlugin.swiftに書きます。以下がデフォルトの状態です。デフォルトでは、関数の分岐がないのですが、handle という関数にて分岐を行なっていきます。(後述)

PluginDemoPlugin.swift
import Flutter
import UIKit

public class PluginDemoPlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "plugin_demo", binaryMessenger: registrar.messenger())
    let instance = PluginDemoPlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
  }

  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    result("iOS " + UIDevice.current.systemVersion)
  }
}

handleの関数で、関数名を分岐する場合はこんな感じです。

PluginDemoPlugin.swift
  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
-       result("iOS " + UIDevice.current.systemVersion)
+       switch call.method {
+       case "selectAppsToDiscourage":
+           // スクリーンタイムAPIの認証のコードをswiftでかく..
+           result(nil)
+       case "encourageAll":
+           // 全部解放するコードをswiftで書く..
+           result(nil)
+       default:
+           result(FlutterMethodNotImplemented)
+       } 
  }

plugin_demo_platform_interface.dart にあたるファイルは今回いじりませんでした。

これらの実装をしたのち、example/lib/main.dartにてpluginを呼び出して、動作するか確認します。

example/lib/main.dart
  final _pluginDemoPlugin = PluginDemo();
  final platformVersion = await _pluginDemoPlugin.getPlatformVersion()

LicenseとCHANGELOG.mdの記入

下記記事を参考にさせていただきました!

https://gaprot.jp/2022/03/22/published-from-flutter-package-creation/

最終的なLicense

https://github.com/kboy-silvergym/screen_time_api_ios/blob/main/LICENSE

最終的なCHANGELOG

https://github.com/kboy-silvergym/screen_time_api_ios/blob/main/CHANGELOG.md

README.mdの記入

READMEはもちろん自由ですが、一番上にサムネイルがあると見栄えが良くなるので、ChatGPTのDALL-E 3のプラグインを使って作ってもらったものを貼ってみました。

最終的なREADME.md

https://github.com/kboy-silvergym/screen_time_api_ios/blob/main/README.md

公開

ドライランして問題ないか確認。

dart pub publish --dry-run

問題なければドライランを外してpublishします。

dart pub publish

以上です!

以下のurlで確認することができます!

https://pub.dev/packages/screen_time_api_ios

参考

以下の記事を大いに参考にしました🙏

https://gaprot.jp/2022/03/22/published-from-flutter-package-creation/

Flutter大学

Discussion