떨림 파악: 플러그인 만들기
우선, 당신은 pub.dev에서 검색을 시도해 보았습니다. 누군가가 제 상황을 만났고 이런 상황을 해결하는 소프트웨어 패키지를 개발했고 지역 사회와 매우 우호적으로 공유했습니다.불행하게도, 당신은 문제를 해결할 방법을 찾지 못했고, 해결 방안 하나만 남았습니다. 플러그인을 만드는 것입니다.
하지만 잠깐만, 우선 플러그인이 무엇인지 알려줘야 해.진동 생태계에는 두 가지 종류의 가방이 있다.
만약 안드로이드 스튜디오를 사용한다면, 파일 -> 새로 만들기 -> 새 진동 프로젝트에 들어갈 수 있습니다.그리고 진동 플러그를 선택하세요.
명령줄을 사용하여 플러그인을 만들 수도 있습니다.
flutter create --template=plugin
플러그인을 개발할 플랫폼과 사용할 언어도 지정할 수 있습니다flutter create --org com.example --template=plugin --platforms=android,ios -I swift -a kotlin flutter_is_awesome
이것은 flutter_is_awesome
라는 플러그인을 만들 것입니다. iOS 부분은 Swift에 있고, 안드로이드 부분은 Kotlin에 있습니다.시스템 연락처 선택기를 표시하는 플러그인을 만들 것입니다.
플러그인 해부
이것이 바로 만들 내용입니다.
다음과 같은 기능이 있습니다.
android
: 위와 같지만 iOS에 적용됩니다.iOS
: 이 폴더는 플러그인의 모든Dart 섹션을 포함하고 이 섹션은 응용 프로그램에서 호출됩니다.lib
: 여기에서 플러그인 개발 테스트를 할 것입니다.test
라는 a채널을 사용하여Dart부분과 본기부분 간에 통신을 하는데 이것은 마치 터널과 같다.Dart부분은 메시지를 보내고 본기부분은 이 메시지를 감청하여 반응한다.이것은 또한 본 컴퓨터 부분에서dart 부분으로 메시지를 보내는 데도 사용할 수 있지만, 본고는 이 점을 소개하지 않을 것이다.Google 플러그인은 오직 하나의 기능만 있습니다. 이 기기의 연락처 선택기를 보여줍니다. 사용자가 연락처를 선택하고 선택한 연락처의 이름을 사용자에게 되돌려줍니다.
이 예에서, 우리는Dart 부분에 간단한 문자열을 되돌려 주지만, 지도나 목록을 사용하여 더욱 복잡한 데이터 구조를 되돌려 줍니다. 플러그인이 지원하는 데이터 형식 목록 here 을 찾을 수 있습니다.
이제 플러그인을 만들고 그 기능을 정의했습니다. 이런 것들을 해야 합니다.
안드로이드 코드
플러그인을 만들면 기본 클래스가 생성됩니다. example
과 MethodChannel
두 가지 방법을 포함합니다.플러그인이 초기화되었을 때, 첫 번째로 호출되었습니다.dart 부분과 통신하는 채널을 만들고, 채널의 정보를 감청하기 시작합니다.채널에 새로운 소식이 있을 때 두 번째 메시지를 호출합니다.이것은 두 가지 인자가 있습니다. onAttachedToEngine
호출된 세부 사항 (방법과 최종 인자) 과 onMethodCall
은 결과를 dart 위젯으로 보내는 데 사용됩니다.
class FlutterIsAwesomePlugin: FlutterPlugin, MethodCallHandler {
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_is_awesome")
channel.setMethodCallHandler(this)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getAContact") {
} else {
result.notImplemented()
}
}
플러그인에 변수를 정의합니다. 이 변수를 잠시 후에 사용하겠습니다
val PICK_CONTACT_RESULT_CODE = 36
var act: android.app.Activity? = null
private lateinit var channel : MethodChannel
private lateinit var result: Result
현재 우리는 call
와 result
프로토콜을 실현해야 한다. 우리는 연락처 선택기를 표시하는 데 사용할 활동을 검색하기 위해 이 프로토콜을 필요로 한다.
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
act = binding.activity
binding.addActivityResultListener(this)
}
override fun onDetachedFromActivityForConfigChanges() {
act = null;
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
act = binding.activity
binding.addActivityResultListener(this)
}
override fun onDetachedFromActivity() {
act = null;
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
return false
}
유일하게 부족한 부분은 연락처 선택기를 표시하고 결과를 검색하는 코드입니다.저희ActivityAware
에서 연락처 선택 활동을 시작하여 PluginRegistry.ActivityResultListener
에서 결과를 검색하고 저희가 저장한 결과 대상으로dart부품에 보냅니다.
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
this.result = result //saves the result to call it when the user selects a contact
if (call.method == "getAContact") {
val intent = Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)
act?.startActivityForResult(intent, PICK_CONTACT_RESULT_CODE)
} else {
result.notImplemented()
}
}
...
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
if (requestCode == PICK_CONTACT_RESULT_CODE) {
if (resultCode == Activity.RESULT_OK) {
if (data != null) {
val contactData = data.data
val c = act!!.contentResolver.query(contactData!!, null, null, null, null)
if (c!!.moveToFirst()) {
val name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
result.success(name)
return true
}
}
}
}
return false
}
안드로이드 부분 완성!✅
iOS 코드
iOS 부분은 안드로이드 부분과 매우 유사할 것입니다. 여기에는 onMethodCall
함수가 있습니다. 이것은 안드로이드에서 본 onActivityResult
함수와 register
함수에 해당하며, 새로운 메시지가 도착할 때 호출됩니다.
public class SwiftFlutterIsAwesomePlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "flutter_is_awesome", binaryMessenger: registrar.messenger())
let instance = SwiftFlutterIsAwesomePlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "getAContact" {
} else {
result(FlutterMethodNotImplemented)
}
}
}
현재 우리는 새로운 클래스 onAttachedToEngine
를 만들어야 한다. 이 클래스는 연락처 선택기 보기 컨트롤러의 리셋을 받고 플러그인 클래스를 알린다.이것은 두 개의 블록 변수 handle
와 ContactPickerDelegate
가 있는데, 선택기가 onSelectContact
프로토콜로 이 종류를 알릴 때 호출됩니다.
import Foundation
import ContactsUI
class ContactPickerDelegate: NSObject, CNContactPickerDelegate {
public var onSelectContact: (CNContact) -> Void
public var onCancel: () -> Void
init(onSelectContact: @escaping (CNContact) -> Void,
onCancel: @escaping () -> Void) {
self.onSelectContact = onSelectContact
self.onCancel = onCancel
super.init()
}
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
picker.presentingViewController?.dismiss(animated: true, completion: nil)
onSelectContact(contact)
}
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
picker.presentingViewController?.dismiss(animated: true, completion: nil)
onCancel()
}
}
지금 우리가 해야 할 일은 onCancel
메시지를 받을 때 연락처 선택기를 표시하는 것입니다. 따라서 플러그인 클래스에 추가합니다.
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "getAContact" {
getAContact(withResult: result)
} else {
result(FlutterMethodNotImplemented)
}
}
//save the contact picker, so it's not deallocated
var contactPickerDelegate: ContactPickerDelegate?
private func getAContact(withResult result: @escaping FlutterResult) {
let contactPicker = CNContactPickerViewController()
contactPickerDelegate = ContactPickerDelegate(onSelectContact: { contact in
//sends the result back to dart
result(contact.givenName + contact.familyName)
self.contactPickerDelegate = nil //set to nil, so it's removed from memory
},
onCancel: {
result(nil)
self.contactPickerDelegate = nil //set to nil, so it's removed from memory
})
contactPicker.delegate = contactPickerDelegate
let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow })
let rootViewController = keyWindow?.rootViewController
DispatchQueue.main.async {
rootViewController?.present(contactPicker, animated: true)
}
}
iOS 부분 완성!✅
성도 코드
퍼즐의 마지막 조각🧩 플러그인을 만드는 성도 부분으로 모든 다른 부분을 붙입니다.
class FlutterIsAwesome {
static const MethodChannel _channel =
const MethodChannel('flutter_is_awesome');
static Future<String> getAContact() async {
final String contact = await _channel.invokeMethod('getAContact');
return contact;
}
}
보시다시피 채널에 있는 방법 CNContactPickerDelegate
을 사용해서 결과를 기다리고 되돌려줍니다.본 기기의 위젯과 상호작용하는 모든 함수는 비동기적이며 getAContact
로 되돌아옵니다.
이제 플러그인만 테스트하면 됩니다. 예시 폴더에서 간단한 프로그램을 완성했습니다. 단추와 탭만 있으면 모든 것이 정상인지 확인할 수 있습니다.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_is_awesome/flutter_is_awesome.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _contact = 'Unknown';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter is Awesome'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
MaterialButton(
color: Colors.red,
textColor: Colors.white,
child: Text('Picker'),
onPressed: () => _getAContact(),
),
Text(_contact ?? '')
],
),
),
),
);
}
_getAContact() async {
String contact;
try {
contact = await FlutterIsAwesome.getAContact();
} on PlatformException {
contact = 'Failed to get contact.';
}
if (!mounted) return;
setState(() {
_contact = contact;
});
}
}
다음은 최종 결과입니다.
결론
플러그인의 최종 코드 GitHub link 를 찾을 수 있습니다.
우리가 여기서 개발한 것은 기본 예시입니다.dart 부분에만 문자열을 되돌려줍니다. 그러나 앞에서 말한 바와 같이, 당신은 더욱 복잡한 데이터 구조를 되돌려받을 수 있고, getAContact
함수를 호출할 때도 본 컴퓨터 부분에 파라미터를 전달할 수 있습니다.
네가 플러그인으로 할 수 있는 일은 거의 무한하다. 우리는 표면에 막 닿았고, 극한은 너의 상상력이다.
Reference
이 문제에 관하여(떨림 파악: 플러그인 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/theotherdevs/mastering-flutter-create-a-plugin-5h63
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
class FlutterIsAwesomePlugin: FlutterPlugin, MethodCallHandler {
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_is_awesome")
channel.setMethodCallHandler(this)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getAContact") {
} else {
result.notImplemented()
}
}
val PICK_CONTACT_RESULT_CODE = 36
var act: android.app.Activity? = null
private lateinit var channel : MethodChannel
private lateinit var result: Result
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
act = binding.activity
binding.addActivityResultListener(this)
}
override fun onDetachedFromActivityForConfigChanges() {
act = null;
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
act = binding.activity
binding.addActivityResultListener(this)
}
override fun onDetachedFromActivity() {
act = null;
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
return false
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
this.result = result //saves the result to call it when the user selects a contact
if (call.method == "getAContact") {
val intent = Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)
act?.startActivityForResult(intent, PICK_CONTACT_RESULT_CODE)
} else {
result.notImplemented()
}
}
...
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
if (requestCode == PICK_CONTACT_RESULT_CODE) {
if (resultCode == Activity.RESULT_OK) {
if (data != null) {
val contactData = data.data
val c = act!!.contentResolver.query(contactData!!, null, null, null, null)
if (c!!.moveToFirst()) {
val name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
result.success(name)
return true
}
}
}
}
return false
}
iOS 부분은 안드로이드 부분과 매우 유사할 것입니다. 여기에는
onMethodCall
함수가 있습니다. 이것은 안드로이드에서 본 onActivityResult
함수와 register
함수에 해당하며, 새로운 메시지가 도착할 때 호출됩니다.public class SwiftFlutterIsAwesomePlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "flutter_is_awesome", binaryMessenger: registrar.messenger())
let instance = SwiftFlutterIsAwesomePlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "getAContact" {
} else {
result(FlutterMethodNotImplemented)
}
}
}
현재 우리는 새로운 클래스 onAttachedToEngine
를 만들어야 한다. 이 클래스는 연락처 선택기 보기 컨트롤러의 리셋을 받고 플러그인 클래스를 알린다.이것은 두 개의 블록 변수 handle
와 ContactPickerDelegate
가 있는데, 선택기가 onSelectContact
프로토콜로 이 종류를 알릴 때 호출됩니다.import Foundation
import ContactsUI
class ContactPickerDelegate: NSObject, CNContactPickerDelegate {
public var onSelectContact: (CNContact) -> Void
public var onCancel: () -> Void
init(onSelectContact: @escaping (CNContact) -> Void,
onCancel: @escaping () -> Void) {
self.onSelectContact = onSelectContact
self.onCancel = onCancel
super.init()
}
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
picker.presentingViewController?.dismiss(animated: true, completion: nil)
onSelectContact(contact)
}
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
picker.presentingViewController?.dismiss(animated: true, completion: nil)
onCancel()
}
}
지금 우리가 해야 할 일은 onCancel
메시지를 받을 때 연락처 선택기를 표시하는 것입니다. 따라서 플러그인 클래스에 추가합니다. public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "getAContact" {
getAContact(withResult: result)
} else {
result(FlutterMethodNotImplemented)
}
}
//save the contact picker, so it's not deallocated
var contactPickerDelegate: ContactPickerDelegate?
private func getAContact(withResult result: @escaping FlutterResult) {
let contactPicker = CNContactPickerViewController()
contactPickerDelegate = ContactPickerDelegate(onSelectContact: { contact in
//sends the result back to dart
result(contact.givenName + contact.familyName)
self.contactPickerDelegate = nil //set to nil, so it's removed from memory
},
onCancel: {
result(nil)
self.contactPickerDelegate = nil //set to nil, so it's removed from memory
})
contactPicker.delegate = contactPickerDelegate
let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow })
let rootViewController = keyWindow?.rootViewController
DispatchQueue.main.async {
rootViewController?.present(contactPicker, animated: true)
}
}
iOS 부분 완성!✅ 성도 코드
퍼즐의 마지막 조각🧩 플러그인을 만드는 성도 부분으로 모든 다른 부분을 붙입니다.
class FlutterIsAwesome {
static const MethodChannel _channel =
const MethodChannel('flutter_is_awesome');
static Future<String> getAContact() async {
final String contact = await _channel.invokeMethod('getAContact');
return contact;
}
}
보시다시피 채널에 있는 방법 CNContactPickerDelegate
을 사용해서 결과를 기다리고 되돌려줍니다.본 기기의 위젯과 상호작용하는 모든 함수는 비동기적이며 getAContact
로 되돌아옵니다.
이제 플러그인만 테스트하면 됩니다. 예시 폴더에서 간단한 프로그램을 완성했습니다. 단추와 탭만 있으면 모든 것이 정상인지 확인할 수 있습니다.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_is_awesome/flutter_is_awesome.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _contact = 'Unknown';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter is Awesome'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
MaterialButton(
color: Colors.red,
textColor: Colors.white,
child: Text('Picker'),
onPressed: () => _getAContact(),
),
Text(_contact ?? '')
],
),
),
),
);
}
_getAContact() async {
String contact;
try {
contact = await FlutterIsAwesome.getAContact();
} on PlatformException {
contact = 'Failed to get contact.';
}
if (!mounted) return;
setState(() {
_contact = contact;
});
}
}
다음은 최종 결과입니다.
결론
플러그인의 최종 코드 GitHub link 를 찾을 수 있습니다.
우리가 여기서 개발한 것은 기본 예시입니다.dart 부분에만 문자열을 되돌려줍니다. 그러나 앞에서 말한 바와 같이, 당신은 더욱 복잡한 데이터 구조를 되돌려받을 수 있고, getAContact
함수를 호출할 때도 본 컴퓨터 부분에 파라미터를 전달할 수 있습니다.
네가 플러그인으로 할 수 있는 일은 거의 무한하다. 우리는 표면에 막 닿았고, 극한은 너의 상상력이다.
Reference
이 문제에 관하여(떨림 파악: 플러그인 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/theotherdevs/mastering-flutter-create-a-plugin-5h63
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
class FlutterIsAwesome {
static const MethodChannel _channel =
const MethodChannel('flutter_is_awesome');
static Future<String> getAContact() async {
final String contact = await _channel.invokeMethod('getAContact');
return contact;
}
}
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_is_awesome/flutter_is_awesome.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _contact = 'Unknown';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter is Awesome'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
MaterialButton(
color: Colors.red,
textColor: Colors.white,
child: Text('Picker'),
onPressed: () => _getAContact(),
),
Text(_contact ?? '')
],
),
),
),
);
}
_getAContact() async {
String contact;
try {
contact = await FlutterIsAwesome.getAContact();
} on PlatformException {
contact = 'Failed to get contact.';
}
if (!mounted) return;
setState(() {
_contact = contact;
});
}
}
플러그인의 최종 코드 GitHub link 를 찾을 수 있습니다.
우리가 여기서 개발한 것은 기본 예시입니다.dart 부분에만 문자열을 되돌려줍니다. 그러나 앞에서 말한 바와 같이, 당신은 더욱 복잡한 데이터 구조를 되돌려받을 수 있고,
getAContact
함수를 호출할 때도 본 컴퓨터 부분에 파라미터를 전달할 수 있습니다.네가 플러그인으로 할 수 있는 일은 거의 무한하다. 우리는 표면에 막 닿았고, 극한은 너의 상상력이다.
Reference
이 문제에 관하여(떨림 파악: 플러그인 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/theotherdevs/mastering-flutter-create-a-plugin-5h63텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)