1. 플러그인 프로젝트 생성
flutter create --org com.example --template=plugin --platforms=android,ios -i swift hello_world
생성된 플러그인 클래스 확인
/pubspec.yaml 파일의 fultter - plugin - platforms 에서 각 플랫폼별로 패키지명이나 클래스를 확인할 수 있다.
flutter:
plugin:
ios:
pluginClass: HelloWorldPlugin
./lib 하위에 dart 파일들이 생성된다.
hello_world.dart
hello_world_platform_interface.dart
hello_world_method_channel.dart
이 파일은 dart에서 각 플랫폼의 함수를 호출하는 코드로 플랫폼 인터페이스와 메쏘드 채널을 구현하고 있다.
./example 하위에는 dart에서 이 plugin을 호출하는 예제로 구성되어 있다.
2. API 구현
1) PlatformInterface
플랫폼 api 정의
lib/hello_world_platform_interface.dart
기본적인 인스턴스 할당과 구현이 필요한 인터페이스 메쏘드들을 정의
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
abstract class HelloWorldPlatform extends PlatformInterface {
HelloWorldPlatform() : super(token: _token);
static final Object _token = Object();
static HelloWorldPlatform _instance = MethodChannelHelloWorld();
static HelloWorldPlatform get instance => _instance;
static set instance(HelloWorldPlatform instance) {
PlatformInterface.verityToken(instance, _token);
_instance = instance;
}
Future<String>? getPlatformVersion() {
throw UnimplementedError('platformVersion() has not been implemented.');
}
}
2) MethodChannel
lib/hello_world_method_channel.dart
플랫폼 인터페이스의 구현부로 실제 플랫폼의 메쏘드 이름을 매핑해 호출하고 결과를 반환
채널명이 "hello_world" 인 메쏘드 채널 생성
해당 메쏘드 채널의 특정 메쏘드 호출
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'hello_world_platform_interface.dart';
// api 구현부
class MethodChannelHelloWorld extends HelloWorldPlatform {
@visibleForTesting
final methodChannel = const MethodChannel('hello_world');
@override
Future<String?> getPlatformVersion() async {
final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
return version;
}
}
3) API 메인 클래스
/lib/hello_world.dart
import 'hello_world_platform_interface.dart'
class HelloWorld {
Future<String?> getPlatformVersion() {
return HelloWorldPlatform.instance.getPlatformVersion();
}
}
3. iOS 플러그인 구현
dart에서 호출할 메쏘드는 정의되었으니 각 플랫폼별로 해당 메쏘드를 구현해 주어야한다.
플랫폼별로 구현이 차이가 있는데, AOS, iOS의 경우 FlutterPlugin, Windows의 경우 flutter::Plugin 을 상속받은 클래스에서 메소드 호출 여부를 위한 메쏘드를 제공한다.
FlutterPlugin 클래스가 해당 메쏘드와 바인드되도록 하기위해 FlutterPluginRegistrar or flutter::PluginRegistrarManager 등을 사용해 해당 클래서를 등록해 주어야 한다.
생성된 샘플에서는 static 메쏘드로 채널명이 "hello_world" 인 메쏘드 채널을 등록한다.
이후, FlutterPlugin 클래스의 handle(_ call: result:) 를 작성한다.(AOS는 onMethodCall)
swift 로 프로젝트 생성 시
/ios/Classes/HelloWorldPlugin.swift
import Flutter
public class HelloWorldPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "hello_world", binaryMessenger: registrar.messenger())
let instance = HelloWorldPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
return IODevice.current.systemVersion
}
}
objc로 프로젝트 생성 시
/ios/Classes/HelloWorldPlugin.h, .m
@interface HelloWorldPlugin : NSObject<FlutterPlugin>
@end
@implementation HelloPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"hello_world" binaryMessenger:[registrar messenger]];
HelloWorldPlugin* instance = [[HelloWorldPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if (@"getPlatformVersion" isEqualToString:call.method]) {
result([@"" stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
} else {
result(FlutterMethodNotImplemented);
}
}
@end
4. 샘플 앱에서 플러그인 사용
example/pubspec.yaml
1) dependency 설정
dependencies:
flutter:
sdk: flutter
hello_world:
path: ../
2) 자동생성 등록 루틴
example/ios/Runner/GeneratedPluginRegistrant.h, .m
프로젝트 생성 후에는 이 메쏘드가 존재하지 않으며, 앱 build 시에 자동 생성(flutter build ios --no-codesign)
플러그인 구현부의 static 메쏘드를 호출해 메쏘드채널과 핸들러를 등록한다.
@interface GeneratedPluginRegistrant: NSObject
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry;
@end
@impleementation GeneratedPluginRegistrant
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
[HelloWorldPlugin registerWithRegistrar: [registry registrarForPlugin:@"HelloWorldPlugin"]];
}
3) AppDelegate 플러그인 등록
실제 AppDelegate는 Flutter 내부에 있으며, FlutterAppDelegate 를 상속받아 생성된 등록 루틴을 호출한다.
import Flutter
@UIApplicationMain
@objc class Adddelegate: FlutterAppDelegate {
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
4) 플러그인 API 사용
example/lib/main.dart
// entry point
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
// api 객체 생성 및 사용
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
final _helloWorldPlugin = HelloWorld();
Future<void> initPlaotformState() async {
String platformVersion;
try {
platformVersion = await _helloWorldPlugin.getPlatformVersion() ?? 'unknown';
} on PlatformException {
platformVersion = 'faliled';
}
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
@Override
Widget build(BuildContext context) {
return MaterialApp(home:
Scaffold(
appBar: AppBar(title: const Text('Plugin example app'),
body: Center(child: Text('version: $_platformVersion')
)
);
}
}
'프로그래밍 > Flutter' 카테고리의 다른 글
[flutter] 특정 값에 따라 Widget 변경 (0) | 2023.04.06 |
---|---|
[flutter] Plugin UIView 사용하기 (0) | 2023.04.04 |
[flutter] iOS plugin 에서 local framework 설정 (0) | 2023.03.30 |
[flutter] 플러그인 프로젝트 구현 절차 (0) | 2023.03.29 |
[flutter] iOS 기본 모듈 구성 방식 (0) | 2023.03.22 |