Flutter

[Flutter] 휴대폰에 저장된 연락처 가져오는 법 & 타입 시스템

hminor 2023. 8. 7. 17:54

폰에 저장된 연락처 몰래 가져오는 법 & 타입시스템

  • 연락처를 꺼내는 방법으로는
    • 패키지를 하나 설치해야 함
    • pubspec.yaml에서 contacts_service를 설치하기!
    • 물론 버전은 다를 수 있지만 contacts_service: ^0.6.3 작성 후 전구에서 pub get을 해주기
    dependencies:
      flutter:
        sdk: flutter
      permission_handler: ^8.3.0
      contacts_service: ^0.6.3
    
    • 이후 main.dart의 상단에 호출하기
    import 'package:contacts_service/contacts_service.dart';
    
    • 설치를 한 다음엔 무조건 실행되고 있는 프로그램을 중지하고 재실행을 시켜야함!!
  • 이후 ContactsService.getContacts() 로 연락처 리스트를 가져올 수 있다.
    • 여기서 await을 추가해준 이유는 print()를 실행 시까지 해당 함수가 완료되지 못하면 에러가 발생하기 때문!
    • 배열로 값이 들어 오기에 배열만 잘 다루면 원하는 값을 가져올 수 있다.
  • getPermission() async{ var status = await Permission.contacts.status; // 연락처 권한을 주었는지 대한 여부 if (status.isGranted) { print('허락됨'); var contacts = await ContactsService.getContacts(); print(contacts[0].givenName); }
  • 또한 해당 함수 실행시 연락처에 값을 추가하고자 한다면
    • 클래스로 부터 객체를 생성 후 추가할 수 있는데
      • 여기서 원래 클래스로부터 인스턴스를 생성할 때 new를 붙여줘야 하지만
      • flutter에서는 붙이지 않아도 된다고 한다.
    getPermission() async{
        var status = await Permission.contacts.status; // 연락처 권한을 주었는지 대한 여부
        if (status.isGranted) {
          print('허락됨');
          var contacts = await ContactsService.getContacts();
          print(contacts[0].givenName);
          var newPerson = Contact();
          newPerson.givenName = '간주';
          newPerson.familyName = '중';
          await ContactsService.addContact(newPerson);
      }
    
  • 이후 현재 반복문으로 보여지고 있는 목록을 연락처에 있는 사람들로 대체하기
    • 여기서 문제는 Dart는 타입을 꼭 지켜줘야하는 TypeScript 와 유사하기에
    • 타입을 꼭 지켜줘야 한다.
    • 그래서 해결책으로는 아래와 같다.
      • 타입 캐스팅(좋지 못한 방법이라고 한다)
      • Union Type ( 변수 하나에 타입 여러 개 설정 가능, 설치 후 사용하면 된다고 함)
      • 기존 배열을 빈 리스트로 만들어 type을 List<dynamic>으로 만들어주기
        • dynamic은 어떠한 타입도 가능하다는 것을 의미
      • 배열 생성 시 미리 타입을 명시할 수 도 있음
        • List<int> number = [1,2,3,4,5]
    • 우선 강의에서는 List<dynamic>으로 빈 리스트만 가지고 있는 리스트를 생성 후 연락처에 있는 데이터를 list에 setState로 담아주기
  • 아래 코드는 현재 버튼을 클릭하게 되면 연락처에 있는 유저의 이름을 보여주도록 하는 코드
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:contacts_service/contacts_service.dart';

void main() {
  runApp(
      MaterialApp(
        home: MyApp()
      )
  );
}

class MyApp extends StatefulWidget {
  MyApp({super.key});
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  getPermission() async{
    var status = await Permission.contacts.status; // 연락처 권한을 주었는지 대한 여부
    if (status.isGranted) {
      print('허락됨');
      var contacts = await ContactsService.getContacts();
      setState(() {
        person = contacts;
      });
    } else if (status.isDenied) {
      print('거절됨');
      Permission.contacts.request(); // 허락해달라고 팝업띄우는 코드
    }
  }

  var a = 1;
  var total = 3;
  var person = [];
  // var cnt = [0, 0, 0];
  var title = 'Contact';

  changeNumber(){
    setState(() {
      total++;
    });
  }

  changeState(value){
    setState(() {
      person.add(value);
    });
  }

  deleteState(idx){
    setState(() {
      person.removeAt(idx);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          showDialog(context: context, builder: (context){
            return Dialog(
              child: Modal(state: title, changeNumber: changeNumber, changeState:changeState)
            );
          });
        },
      ),
      appBar: AppBar(title: Text(person.length.toString()),actions: [
        IconButton(onPressed: (){
          getPermission();
        }, icon: Icon(Icons.contacts))
      ],),
      body: ListView.builder(
          itemCount: person.length,
          itemBuilder: (c,i){
            return ListTile(
              leading: Icon(Icons.person),
              title: Text(person[i].givenName)
            );
          }
      ),
    );
  }
}

숙제

  • 모달창에서 완료를 누르면 입력한 이름이 연락처에 추가되도록 하기!
    • 우선은 이름만 추가하도록 하기!
  • 해결 방법으로는 우선 모달창으로 getPermission 메서드를 전달해서 연락처에 추가 후 바로 person 리스트가 연락처에 있는 목록을 다시 갱신되도록 만들기!
  • 그리고 모달창에서는 Contact 인스턴스를 생성 후
    현재 입력된 input 데이터 값을 해당 인스턴스의 givenName 에 넣고 연락처에 담아주기!
  • 이때 로직의 순서대로 흘러갈 수 있도록 하기 위해 async, awiat을 사용함
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:contacts_service/contacts_service.dart';

void main() {
  runApp(
      MaterialApp(
        home: MyApp()
      )
  );
}

class MyApp extends StatefulWidget {
  MyApp({super.key});
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  getPermission() async{
    var status = await Permission.contacts.status; // 연락처 권한을 주었는지 대한 여부
    if (status.isGranted) {
      print('허락됨');
      var contacts = await ContactsService.getContacts();
      setState(() {
        person = contacts;
      });
    } else if (status.isDenied) {
      print('거절됨');
      Permission.contacts.request(); // 허락해달라고 팝업띄우는 코드
    }
  }

  var a = 1;
  var total = 3;
  var person = [];
  // var cnt = [0, 0, 0];
  var title = 'Contact';

  changeNumber(){
    setState(() {
      total++;
    });
  }

  changeState(value){
    setState(() {
      person.add(value);
    });
  }

  deleteState(idx){
    setState(() {
      person.removeAt(idx);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          showDialog(context: context, builder: (context){
            return Dialog(
              child: Modal(state: title, changeNumber: changeNumber, changeState:changeState, getPermission:getPermission)
            );
          });
        },
      ),
      appBar: AppBar(title: Text(person.length.toString()),actions: [
        IconButton(onPressed: (){
          getPermission();
        }, icon: Icon(Icons.contacts))
      ],),
      body: ListView.builder(
          itemCount: person.length,
          itemBuilder: (c,i){
            return ListTile(
              leading: Icon(Icons.person),
              title: Text(person[i].givenName)
            );
          }
      ),
    );
  }
}

class Modal extends StatelessWidget {
  Modal({super.key, this.state, this.changeNumber, this.changeState, this.getPermission});
  final state;
  final changeNumber;
  final getPermission;
  var changeState;
  var inputData = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 400,
      margin: EdgeInsets.fromLTRB(5, 0, 5, 0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            margin: EdgeInsets.all(5),
            child: Text(state, style: TextStyle(fontSize: 40, fontWeight: FontWeight.w900)),
          ),
          Container(
            margin: EdgeInsets.all(5),
            child: TextField( controller: inputData, style: TextStyle(fontSize: 30),),
          ),
          Container(
            margin: EdgeInsets.all(5),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: [
                Container(
                  margin: EdgeInsets.fromLTRB(5, 0, 5, 0),
                  child: TextButton(onPressed: (){
                    Navigator.pop(context);
                  }, child: Text('Cencel', style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),)),
                ),
                Container(
                  margin: EdgeInsets.fromLTRB(5, 0, 5, 0),
                  child: TextButton(onPressed: () async{
                    if (inputData.text != ''){
                      var newPerson = Contact();
                      newPerson.givenName = inputData.text.toString();
                      await ContactsService.addContact(newPerson);
                      await getPermission();
                      Navigator.pop(context);
                    }
                  }, child: Text('OK', style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),)),
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}