美文网首页FlutterFlutter飞起
FlutterPlugin获取手机通讯录

FlutterPlugin获取手机通讯录

作者: 倪大头 | 来源:发表于2021-04-13 17:33 被阅读0次

    用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

    相关文章

      网友评论

        本文标题:FlutterPlugin获取手机通讯录

        本文链接:https://www.haomeiwen.com/subject/ageclltx.html