用Android Studio创建flutter plugin项目:
image.png
创建完成目录长这样:
image.png
主要文件就三个,addressbook_plugin.dart里写flutter代码,AddressbookPlugin.m写iOS代码,安卓代码则是AddressbookPlugin.java
先看flutter代码
addressbook_plugin.dart:
import 'dart:async';
import 'package:flutter/services.dart';
class AddressBookPlugin {
static const MethodChannel _channel =
const MethodChannel('addressbook_plugin');
static Future<String> get addressBook async {
final String contacts = await _channel.invokeMethod('getAddressBook');
return contacts;
}
}
addressbook_plugin是自定义的channel名,用来和原生进行通信的管道名,而getAddressBook则是自定义的方法名,原生根据方法名执行相应操作
接着看iOS代码(OC)
AddressbookPlugin:
#import "AddressbookPlugin.h"
#import <Contacts/Contacts.h>
@implementation AddressbookPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"addressbook_plugin"
binaryMessenger:[registrar messenger]];
AddressbookPlugin* instance = [[AddressbookPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"getAddressBook" isEqualToString:call.method]) {
// 通讯录
[self getAddressBook:result];
} else {
result(FlutterMethodNotImplemented);
}
}
- (void)getAddressBook:(FlutterResult)result {
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
if (status == CNAuthorizationStatusNotDetermined) {
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError* _Nullable error) {
if (error) {
NSLog(@"授权失败");
result(@"没有权限");
} else {
NSLog(@"成功授权");
[self openContact:result];
}
}];
} else if(status == CNAuthorizationStatusRestricted) {
NSLog(@"用户拒绝");
result(@"没有权限");
} else if (status == CNAuthorizationStatusDenied) {
NSLog(@"用户拒绝");
result(@"没有权限");
} else if (status == CNAuthorizationStatusAuthorized) { // 已经授权
// 有通讯录权限 -- 进行下一步操作
[self openContact:result];
}
}
// 有通讯录权限 -- 进行下一步操作
- (void)openContact:(FlutterResult)result {
NSMutableArray *contactsArr = [NSMutableArray array];
// 获取指定的字段,并不是要获取所有字段,需要指定具体的字段
NSArray *keysToFetch = @[CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey];
CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch];
CNContactStore *contactStore = [[CNContactStore alloc] init];
[contactStore enumerateContactsWithFetchRequest:fetchRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
// NSString *givenName = contact.givenName;
// NSString *familyName = contact.familyName;
// NSLog(@"givenName=%@, familyName=%@", givenName, familyName);
// 拼接姓名
NSString *nameStr = [NSString stringWithFormat:@"%@%@", contact.familyName, contact.givenName];
NSArray *phoneNumbers = contact.phoneNumbers;
for (CNLabeledValue *labelValue in phoneNumbers) {
// 遍历一个人名下的多个电话号码
CNPhoneNumber *phoneNumber = labelValue.value;
NSString *string = phoneNumber.stringValue;
// 去掉电话中的特殊字符
string = [string stringByReplacingOccurrencesOfString:@"+86" withString:@""];
string = [string stringByReplacingOccurrencesOfString:@"-" withString:@""];
string = [string stringByReplacingOccurrencesOfString:@"(" withString:@""];
string = [string stringByReplacingOccurrencesOfString:@")" withString:@""];
string = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
string = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLog(@"姓名=%@, 电话号码是=%@", nameStr, string);
[contactsArr addObject:@{@"name": nameStr, @"phone": string}];
}
}];
NSLog(@"共计%ld个号码", contactsArr.count);
NSError *error = nil;
NSData *contactsJsonData = [NSJSONSerialization dataWithJSONObject:contactsArr
options:kNilOptions
error:&error];
NSString *contactsJsonString = [[NSString alloc] initWithData:contactsJsonData
encoding:NSUTF8StringEncoding];
NSLog(@"通讯录Json %@", contactsJsonString);
result(contactsJsonString);
}
@end
在registerWithRegistrar方法中注册通道,在handleMethodCall代理方法中监听方法
上面代码在监听到getAddressBook方法时执行了获取通讯录的操作
获取通讯录使用了下面的系统库
#import <Contacts/Contacts.h>
到这里插件包就写完了,把整个插件包项目文件提交到github上就可以在其他项目中使用这个插件了
现在试试在其他项目中导入这个插件,新建一个项目,打开pubspec.yaml
在dependencies:下导入插件,需要以git路径形式导入,比如
addressbook_plugin:
git: https://github.com/neechen/address_book_plugin.git
image.png
点右上角Pub get导入插件
写一个获取通讯录的方法:
void _getAddressBook() async {
try {
contacts = await AddressBookPlugin.addressBook;
} catch (e) {
print(e);
}
if (contacts.length > 0) {
setState(() {});
}
}
与原生通信的方法都是异步的,这里要用async/await
ios项目中info.plist文件需要加入通讯录权限,否则会失败:
image.png
main.dart代码:
import 'package:addressbook_plugin/addressbook_plugin.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '通讯录插件测试',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: '通讯录插件测试'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String contacts = '';
void _getAddressBook() async {
try {
contacts = await AddressBookPlugin.addressBook;
} catch (e) {
print(e);
}
if (contacts.length > 0) {
setState(() {});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Text(
'$contacts',
style: TextStyle(
fontSize: 15,
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _getAddressBook,
child: Icon(Icons.contacts),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
效果:
image.png
网友评论