flutter

[Flutter] 연락처 접근

킹왕짱지지 2024. 3. 27. 15:33

* 권한 요청은 앞선 글을 확인 

 

1. 연락처 꺼내는 패키지 설치

pubspec.yaml의 dependencies에 추가

contacts_service: ^0.6.3

 

main.dart

import 'package:contacts_service/contacts_service.dart';

 

2. 연락처 가져오기

var contacts = await ContactsService.getContacts(); //오래 걸리는 코드
      print(contacts); // 연락처 담겨있음

 

- 함수 전체코드

  getPermission() async {
    var status = await Permission.contacts.status;
    if (status.isGranted) {
      print('허락됨');
      var contacts = await ContactsService.getContacts(); //오래 걸리는 코드
      print(contacts); // 연락처 담겨있음
    } else if (status.isDenied) {
      print('거절됨');
      Permission.contacts.request(); // 허락해달라고 팝업 띄우는 코드
      openAppSettings(); //앱 설정 화면 켜줌
    }
  }

 

 

3. 폰 연락처에 강제 추가하는 법

var newPerson = new Contact(); //폰에 연락처 강제 추가(new 키워드 생략 가능)
      newPerson.givenName='송송';
      newPerson.familyName='최';
      ContactsService.addContact(newPerson);

 

-전체코드

  getPermission() async {
    var status = await Permission.contacts.status;
    if (status.isGranted) {
      print('허락됨');
      var contacts = await ContactsService.getContacts(withThumbnails: false); //오래 걸리는 코드, 괄호안은 썸내일은 가져오지 않는 것
      print(contacts[0].displayName); // 연락처 이름 담겨있음
      print(contacts[0].phones![0].value.toString()); // 번호 담겨있음

      var newPerson = new Contact(); //폰에 연락처 강제 추가(new 키워드 생략 가능)
      newPerson.givenName='송송';
      newPerson.familyName='최';
      ContactsService.addContact(newPerson);

    } else if (status.isDenied) {
      print('거절됨');
      Permission.contacts.request(); // 허락해달라고 팝업 띄우는 코드
      openAppSettings(); //앱 설정 화면 켜줌
    }
  }

 

4. 실제 연락처를 앱에서 보여주려면?

4-1) 리스트로 하는 법

(getPermission 함수 안쪽)

var contacts = await ContactsService.getContacts(withThumbnails: false);
print(contacts[0].givenName)

setState(() {
  name = contacts;
});

var name = []; 또는 List<Contact> name = [];

 

4-2 ) 이름, 연락처를 Map으로 했다면?

(getPermission 안쪽 함수)
for (int i=0; i<contacts.length; i++){
        setState(() {
          name[contacts[i].displayName.toString()]=contacts[0].phones![0].value.toString();
        });
      }
      
      
 Map<String, String> name= {}; 으로 변경

 

4-3) Dialog의 입력을 통해 실제연락처에!! 연락처 추가하는 방법

TextButton(
              child: Text('완료'),
              onPressed: () {
                // widget.addOne(inputData1, inputData2); //화면에는 뜨는데 실제 연락처에는 추가X
                //실제 연락처에 추가 하는 법
                var newContact = Contact();
                newContact.givenName = inputData1;
                newContact.phones = [Item(label: 'mobile', value: inputData2)]; //새로운 연락처 만들기
                ContactsService.addContact(newContact);  //실제로 연락처에 집어넣기
                print(newContact.givenName);
                Navigator.of(context).pop(); //창닫기-세밀한 제어가능
              },
            ),

 

-전체코드

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rive/rive.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({Key? key}) : super(key: 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(withThumbnails: false); //오래 걸리는 코드
      print(contacts[0].displayName); // 이름 담겨있음
      print(contacts[0].phones![0].value.toString()); // 번호 담겨있음

      for (int i=0; i<contacts.length; i++){
        addName(contacts[i].displayName.toString(), contacts[0].phones![0].value.toString());
      }

      var newPerson = new Contact(); //폰에 연락처 강제 추가(new 키워드 생략 가능)
      newPerson.givenName='송송';
      newPerson.familyName='최';
      ContactsService.addContact(newPerson);

    } else if (status.isDenied) {
      print('거절됨');
      Permission.contacts.request(); // 허락해달라고 팝업 띄우는 코드
      openAppSettings(); //앱 설정 화면 켜줌
    }
  }

  var total = 3;
  Map<String, String> name= {};
  var like = [0, 0, 0];

  addName(a, b){
    setState(() {
      name[a]=b;
    });
  }

  addOne(key, value) {
    if (key.length > 0) {
      setState(() {
        name[key] = value;
        print(name);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    var sortedName = Map.fromEntries(
        name.entries.toList()..sort((e1, e2) => e1.key.compareTo(e2.key)));
    return Scaffold(
        floatingActionButton: FloatingActionButton(
          child: Text('다이얼로그'),
          onPressed: () {
            //버튼 눌렀을때 마다 실행
            print(context.findAncestorWidgetOfExactType<
                MaterialApp>()); //조상중에 materialApp이 있으면 출력해주세요
            showDialog(
                context: context,
                barrierDismissible: true, //바깥 영역 터치시 닫을지 여부 결정
                builder: (context) {
                  return DialogUI(addOne: addOne);
                });
          },
        ),
        appBar: AppBar(
          title: Text(total.toString()),
          actions: [
            IconButton(
                onPressed: () {
                  getPermission();
                },
                icon: Icon(Icons.contacts))
          ],
        ),
        body: ListView.builder(
            itemCount: sortedName.length,
            itemBuilder: (context, i) {
              //일반적으로 c,i로 작명
              String key = sortedName.keys.elementAt(i);
              return ListTile(
                leading: Icon(Icons.account_circle),
                title: Text(key),
                subtitle: Text(sortedName[key].toString()),
                trailing: ElevatedButton(
                    child: Text("삭제"),
                    onPressed: () {
                      setState(() {
                        sortedName.remove(key);
                        name.remove(key);
                      });
                    }),
              ); //이 위젯이 3번 반복됨
            }),
        bottomNavigationBar: bottomappbar());
  }
}

class DialogUI extends StatefulWidget {
  DialogUI({Key? key, this.addOne}) : super(key: key);
  final addOne;

  @override
  State<DialogUI> createState() => _DialogUIState();
}

class _DialogUIState extends State<DialogUI> {
  var inputData1 = '';
  var inputData2 = '';

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('Contact'),
      content: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            TextField(
                onChanged: (text) {
                  inputData1 = text;
                },
                decoration: InputDecoration(hintText: '이름')),
            TextField(
                onChanged: (text) {
                  inputData2 = text;
                },
                decoration: InputDecoration(hintText: '전화번호')),
          ]),
      actions: <Widget>[
        Container(
            child: Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            TextButton(
              child: Text('취소'),
              onPressed: () {
                Navigator.pop(context); //창닫기
              },
            ),
            TextButton(
              child: Text('완료'),
              onPressed: () {
                // widget.addOne(inputData1, inputData2); //화면에는 뜨는데 실제 연락처에는 추가X
                //실제 연락처에 추가 하는 법
                var newContact = Contact();
                newContact.givenName = inputData1;
                newContact.phones = [Item(label: 'mobile', value: inputData2)]; //새로운 연락처 만들기
                ContactsService.addContact(newContact);  //실제로 연락처에 집어넣기
                print(newContact.givenName);
                Navigator.of(context).pop(); //창닫기-세밀한 제어가능
              },
            ),
          ],
        ))
      ],
    );
  }
}

//나만의 위젯을 만드는 법
class ShopItem extends StatelessWidget {
  const ShopItem({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      child: Text('안녕'),
    );
  }
}

class bottomappbar extends StatelessWidget {
  const bottomappbar({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 50,
      color: Colors.white24,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          Icon(Icons.call),
          Icon(Icons.call),
          Icon(Icons.call),
        ],
      ),
    );
  }
}

// class HomePage extends StatelessWidget {
//   const HomePage({Key? key}) : super(key: key);
//
//   @override
//   Widget build(BuildContext context) => Scaffold(
//     appBar: AppBar(
//       title: const Text('Rive Animation'),
//       centerTitle: true,
//     ),
//     body: Center(
//       child: Column(
//         mainAxisAlignment: MainAxisAlignment.center,
//         children: [
//           ElevatedButton(
//             child: const Text('Simple Animation'),
//             onPressed: () {
//               Navigator.push(
//                 context,
//                 MaterialPageRoute<void>(
//                   builder: (context) => const SimpleAnimation(),
//                 ),
//               );
//             },
//           ),
//           const SizedBox(
//             height: 20,
//           ),
//           ElevatedButton(
//             child: const Text('Dancing Mascot'),
//             onPressed: () {
//               Navigator.push(
//                 context,
//                 MaterialPageRoute<void>(
//                   builder: (context) => const StateMachineMuscot(),
//                 ),
//               );
//             },
//           ),
//           const SizedBox(
//             height: 20,
//           ),
//           ElevatedButton(
//             child: const Text('Animation time control'),
//             onPressed: () {
//               Navigator.push(
//                 context,
//                 MaterialPageRoute<void>(
//                   builder: (context) => const StateTimeControl(),
//                 ),
//               );
//             },
//           ),
//         ],
//       ),
//     ),
//   );
// }
//
// class SimpleAnimation extends StatelessWidget {
//   const SimpleAnimation({Key? key}) : super(key: key);
//
//   @override
//   Widget build(BuildContext context) => Scaffold(
//     appBar: AppBar(
//       title: const Text('Rive Animation'),
//       centerTitle: true,
//     ),
//     body: Center(
//       child: Column(
//         mainAxisAlignment: MainAxisAlignment.center,
//         children: [
//           Expanded(
//             child: RiveAnimation.network(
//               'https://public.rive.app/community/runtime-files/2191-4327-loader-solicitud-de-cuentas.riv',
//             ),
//           ),
//           Expanded(
//             child: RiveAnimation.asset(
//               'assets/dash_flutter_muscot.riv',
//             ),
//           ),
//         ],
//       ),
//     ),
//   );
// }
//
// class StateMachineMuscot extends StatefulWidget {
//   const StateMachineMuscot({Key? key}) : super(key: key);
//
//   @override
//   _StateMachineMuscotState createState() => _StateMachineMuscotState();
// }
//
// class _StateMachineMuscotState extends State<StateMachineMuscot> {
//   Artboard? riveArtboard;
//   SMIBool? isDance;
//   SMITrigger? isLookUp;
//
//   @override
//   void initState() {
//     super.initState();
//     rootBundle.load('assets/dash_flutter_muscot.riv').then(
//           (data) async {
//         try {
//           final file = RiveFile.import(data);
//           final artboard = file.mainArtboard;
//           var controller =
//           StateMachineController.fromArtboard(artboard, 'birb');
//           if (controller != null) {
//             artboard.addController(controller);
//             isDance = controller.findSMI('dance');
//             isLookUp = controller.findSMI('look up');
//           }
//           setState(() => riveArtboard = artboard);
//         } catch (e) {
//           print(e);
//         }
//       },
//     );
//   }
//
//   void toggleDance(bool newValue) {
//     setState(() => isDance!.value = newValue);
//   }
//
//
//
//   @override
//   Widget build(BuildContext context) => Scaffold(
//     appBar: AppBar(
//       title: const Text('Rive Animation'),
//       centerTitle: true,
//     ),
//     body: riveArtboard == null
//         ? const SizedBox()
//         : Column(
//       children: [
//         Expanded(
//           child: Rive(
//             artboard: riveArtboard!,
//           ),
//         ),
//         Row(
//           mainAxisAlignment: MainAxisAlignment.center,
//           crossAxisAlignment: CrossAxisAlignment.center,
//           children: [
//             Text('Dance'),
//             Switch(
//               value: isDance!.value,
//               onChanged: (value) => toggleDance(value),
//             ),
//           ],
//         ),
//         const SizedBox(height: 12),
//         ElevatedButton(
//           child: const Text('Look up'),
//           onPressed: () => isLookUp?.value = true,
//         ),
//         const SizedBox(height: 12),
//       ],
//     ),
//   );
//
//
// }
//
// //여기가 스터디 코드
// class StateTimeControl extends StatefulWidget {
//   const StateTimeControl({Key? key}) : super(key: key);
//
//   @override
//   _StateTimeControl createState() => _StateTimeControl();
// }
//
// class _StateTimeControl extends State<StateTimeControl> {
//   Artboard? riveArtboard;
//   SMIBool? isDance; //dance 상태 제어 변수
//   SMITrigger? isLookUp; //look up 상태 제어 변수
//
//   @override
//   void initState() {
//     super.initState();
//     rootBundle.load('assets/dash_flutter_muscot.riv').then(
//           (data) async {
//         try {
//           final file = RiveFile.import(data);
//           final artboard = file.mainArtboard;
//           var controller =
//           StateMachineController.fromArtboard(artboard, 'birb');
//           if (controller != null) {
//             artboard.addController(controller);
//             isDance = controller.findSMI('dance');
//             isLookUp = controller.findSMI('look up');
//             isDance?.value = true; // 'Dance' 상태를 기본적으로 활성화
//           }
//           setState(() => riveArtboard = artboard);
//         } catch (e) {
//           print(e);
//         }
//       },
//     );
//   }
//
//   // 'stop dance' 버튼을 눌렀을 때 호출되는 함수
//   // 3초동안 멈췄다가 다시 춤추도록
//   void stopDance() {
//     if (isDance != null && isDance!.value) {
//       setState(() => isDance!.value = false); // 'Dance' 상태를 비활성화하여 춤을 멈춤.
//
//       // 3초 후에 다시 춤을 시작합니다.
//       Future.delayed(Duration(seconds: 3), () {
//         setState(() {
//           if (isDance != null) {
//             isDance!.value = true; // 'Dance' 상태를 다시 활성화하여 춤을 시작합니다.
//           }
//         });
//       });
//     }
//   }
//
//
//   @override
//   Widget build(BuildContext context) => Scaffold(
//     appBar: AppBar(
//       title: const Text('Rive Animation'),
//       centerTitle: true,
//     ),
//     body: riveArtboard == null
//         ? const SizedBox()
//         : Column(
//       children: [
//         Expanded(
//           child: Rive(
//             artboard: riveArtboard!,
//           ),
//         ),
//         Column(
//           mainAxisAlignment: MainAxisAlignment.center,
//           children: [
//         const SizedBox(height: 12),
//         ElevatedButton(
//           child: const Text('Stop Dance'),
//           onPressed: () {
//           stopDance();
//           },
//         ),
//         const SizedBox(height: 12),
//         ElevatedButton(
//           child: const Text('Look up'),
//           onPressed: () => isLookUp?.value = true,
//         ),
//         const SizedBox(height: 12),
//       ],
//     ),
//   ]));
// }