사용권한 permission_handler
https://pub.dev/packages/permission_handler/install
연락처 접근 contacts_service
https://pub.dev/packages/contacts_service/install
android\app\src\main\AndroidManifest.xml
아래 허용 추가
연락처 수정을 할 것이 아니라면 WRITE_CONTACTS
는 빼도된다
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<!--추가-->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
...
ios/Podfile
target 'Runner' do
블럭 아래 post_install
블럭에 접근 권한을 추가해준다
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
## 수정부분
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## 연락처 접근권한
## dart: PermissionGroup.contacts
'PERMISSION_CONTACTS=1',
## dart: PermissionGroup.camera
# 'PERMISSION_CAMERA=1',
]
end
end
end
아래 permission_handler readme를 보면 다양한 접근 권한 예시가 있다
https://pub.dev/packages/permission_handler
ios\Runner\Info.plist
연락처 권한을 얻을때 표시할 메시지를 같이 작성한다
<key>NSContactsUsageDescription</key>
<string>연락처 권한이 필요합니다.</string>
_contacts
변수를 선언할때 List<Contact>?
를 사용해서 사실 null로 초기화를 안해줘도 되는데 ios에서 사용할때는 null safety오류가 떠서 초기화를 해줬다 List<Contact>? _contacts = null; // ios 오류때문에 초기화 해야함
// 연락처 가져오기 기능
Future<void> getContacts() async {
if (await Permission.contacts.request().isGranted) {
// 접근권한을 얻을 시 실행되는 기능
var contacts = await ContactsService.getContacts(
withThumbnails: false,
);
// 가져온 연락처 목록 변수에 할당
setState(() {
_contacts = contacts;
});
// 연락처 목록 모달 열기
showModal();
// Iterate over the contacts and look for the phone number
} else {
// Permission denied, handle the error
// 연락처 접근권한을 얻지 못하면 상황에따라 알림 처리가 필요
}
}
앞서 가져온 연락처 데이터를 ListView를 사용해 리스트로 출력한다
** 주의할점 - 번호는 배열형태로 들어온다
List<Contact> list = {연락처 데이터} // 전체데이터
list.phones // 출력시 아래와 같이 출력
/*
[
Item(
label: 'phone',
value: '123456789',
),
Item(
label: 'phone',
value: '123456789',
),
]
*/
var phoneNumber = list.phones!.isNotEmpty
? c.phones![0].value.toString()
: '연락처가 없습니다';
// 연락처 모달 오픈
Future<void> showModal() async {
showDialog(
context: context,
builder: (context) {
return Dialog(
// 목록 생성
child: ListView.builder(
itemCount: _contacts?.length,
itemBuilder: (BuildContext context, int index) {
Contact c = _contacts!.elementAt(index); // 연락처 element
var userName = c.displayName; // 연락처 이름
// 연락처 번호
var phoneNumber = c.phones!.isNotEmpty
? c.phones![0].value.toString()
: '연락처가 없습니다';
// 버튼으로 렌더링
return TextButton(
onPressed: () {
// 연락처 누를시 실행할 함수
_phoneNumberController.text = phoneNumber.toString();
// 모달 닫기
Navigator.of(context).pop();
},
child: Text(userName ?? ""),
);
},
),
);
},
);
}
결과적으로 '연락처 가져오기' 버튼을 누를 때 아래와 같이 실행할 수 있다
if (_contacts == null) {
getContacts(); // 최초로 가져오기
} else {
showModal(); // 한번 가져온 후 실행
}
import 'package:permission_handler/permission_handler.dart';
import 'package:contacts_service/contacts_service.dart';
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
List<Contact>? _contacts = null; // ios 오류때문에 초기화 해야함
// 연락처 가져오기 기능
Future<void> getContacts() async {
if (await Permission.contacts.request().isGranted) {
var contacts = await ContactsService.getContacts(
withThumbnails: false,
);
// 가져온 연락처 목록 변수에 할당
setState(() {
_contacts = contacts;
});
// 연락처 목록 모달 열기
showModal();
// Iterate over the contacts and look for the phone number
} else {
// Permission denied, handle the error
}
}
// 연락처 모달 오픈
Future<void> showModal() async {
showDialog(
context: context,
builder: (context) {
return Dialog(
child: ListView.builder(
itemCount: _contacts?.length,
itemBuilder: (BuildContext context, int index) {
Contact c = _contacts!.elementAt(index);
var userName = c.displayName;
var phoneNumber = c.phones?.first.value;
return TextButton(
onPressed: () {
_phoneNumberController.text = phoneNumber.toString();
Navigator.of(context).pop();
},
child: Text(userName ?? ""),
);
},
),
);
},
);
}
Widget build(BuildContext context) {
return Container(
child: ElevatedButton(
onPressed: () {
if (_contacts == null) {
getContacts(); // 최초로 가져오기
} else {
showModal(); // 한번 가져온 후 실행
}
},
child: Text(
'연락처에서 선택',
style: TextStyle(
fontSize: 13,
color: Theme.of(context).primaryColorDark,
),
),
),
);
}
}