fluttercommunity / flutter_contacts

Contacts Service - A Flutter plugin to retrieve and manage contacts on Android and iOS devices. Maintainer: @lukasgit
https://pub.dev/packages/contacts_service
MIT License
153 stars 69 forks source link

Weird FATAL EXCEPTION AsyncTask #2 when getting contacts #56

Closed Calamari closed 5 years ago

Calamari commented 5 years ago

Hey guys.

I am in a bit of a pickle right now, since I am trying building an app that needs to reads the mobiles contacts but somehow it just fails miserably at this. And I am missing clues how to debug this – since the error message is less than helpful.

Here is the widget I am trying to run:

class ContactImporter extends StatefulWidget {
  @override
  _ContactImporterState createState() => _ContactImporterState();
}

class _ContactImporterState extends State<ContactImporter> {
  List<Contact> contacts = [];

  @override
  void initState() {
    debugPrint("start loading contacts");
    ContactsService.getContacts().then((foundContacts) {
      debugPrint("done loading contacts" + foundContacts.length.toString());
      setState(() {
        contacts = foundContacts;
      });
    }).catchError((error) {
      debugPrint(error);
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Contacts')),
      body: contacts.length == 0 ? Center(child: Text("Nothing to see here…")) : ListView(
        children: contacts.map((contact) => Text(contact.displayName)).toList(),
      )
    );
  }
}

And here is what the debug console outputs:

I/flutter (20876): start loading contacts
E/AndroidRuntime(20876): FATAL EXCEPTION: AsyncTask #2
E/AndroidRuntime(20876): Process: com.example.contactexample, PID: 20876
E/AndroidRuntime(20876): java.lang.RuntimeException: An error occurred while executing doInBackground()
E/AndroidRuntime(20876):    at android.os.AsyncTask$3.done(AsyncTask.java:354)
E/AndroidRuntime(20876):    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
E/AndroidRuntime(20876):    at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
E/AndroidRuntime(20876):    at java.util.concurrent.FutureTask.run(FutureTask.java:271)
E/AndroidRuntime(20876):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
E/AndroidRuntime(20876):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/AndroidRuntime(20876):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/AndroidRuntime(20876):    at java.lang.Thread.run(Thread.java:764)
E/AndroidRuntime(20876): Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord{3fc343d 20876:com.example.ubercontactedmobile/u0a86} (pid=20876, uid=10086) requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS
E/AndroidRuntime(20876):    at android.os.Parcel.createException(Parcel.java:1942)
E/AndroidRuntime(20876):    at android.os.Parcel.readException(Parcel.java:1910)
E/AndroidRuntime(20876):    at android.os.Parcel.readException(Parcel.java:1860)
E/AndroidRuntime(20876):    at android.app.IActivityManager$Stub$Proxy.getContentProvider(IActivityManager.java:4181)
E/AndroidRuntime(20876):    at android.app.ActivityThread.acquireProvider(ActivityThread.java:5970)
E/AndroidRuntime(20876):    at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2592)
E/AndroidRuntime(20876):    at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1828)
E/AndroidRuntime(20876):    at android.content.ContentResolver.query(ContentResolver.java:786)
E/AndroidRuntime(20876):    at android.content.ContentResolver.query(ContentResolver.java:752)
E/AndroidRuntime(20876):    at android.content.ContentResolver.query(ContentResolver.java:710)
E/AndroidRuntime(20876):    at flutter.plugins.contactsservice.contactsservice.ContactsServicePlugin.getCursor(ContactsServicePlugin.java:152)
E/AndroidRuntime(20876):    at flutter.plugins.contactsservice.contactsservice.ContactsServicePlugin.access$000(ContactsServicePlugin.java:34)
E/AndroidRuntime(20876):    at flutter.plugins.contactsservice.contactsservice.ContactsServicePlugin$GetContactsTask.doInBackground(ContactsServicePlugin.java:125)
E/AndroidRuntime(20876):    at flutter.plugins.contactsservice.contactsservice.ContactsServicePlugin$GetContactsTask.doInBackground(ContactsServicePlugin.java:112)
E/AndroidRuntime(20876):    at android.os.AsyncTask$2.call(AsyncTask.java:333)
E/AndroidRuntime(20876):    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
E/AndroidRuntime(20876):    ... 4 more
E/AndroidRuntime(20876): Caused by: android.os.RemoteException: Remote stack trace:
E/AndroidRuntime(20876):    at com.android.server.am.ActivityManagerService.getContentProviderImpl(ActivityManagerService.java:12188)
E/AndroidRuntime(20876):    at com.android.server.am.ActivityManagerService.getContentProvider(ActivityManagerService.java:12585)

Maybe I am doing something really stupid – which totally might happen since I am fairly new to flutter and stuff – but I think it should work. So if anyone knows what is going on, or how to find the crux, I would be really indebted to you.

Not quite sure what you could need to help, so here is the flutter doctor output:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.0.0, on Linux, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK 28.0.3)
[✓] Android Studio (version 3.2)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
[✓] VS Code (version 1.30.1)
[✓] Connected device (1 available)

• No issues found!

I am trying this in the simulator with a Nexus_5X_api_28_64 device.

Any ideas?

Calamari commented 5 years ago

After more thinking about it, I got it myself. For future reference, this happens when you don't have the permissions to read the contacts. What I was missing was the simple_permissions plugin.

So a basic and valid initialState method could look like this:

  @override
  void initState() {
    SimplePermissions
      .requestPermission(Permission.ReadContacts)
      .then((status) {
        if (status != PermissionStatus.authorized) {
          debugPrint("no read rights. Aborting mission!");
          return;
        }
        debugPrint("start loading contacts");
        ContactsService.getContacts().then((foundContacts) {
          debugPrint("done loading contacts" + foundContacts.length.toString());
          final list = foundContacts.toList();
          list.sort((a, b) => a.givenName.compareTo(b.givenName));
          setState(() {
            contacts = list;
          });
        }).catchError((error) {
          debugPrint(error.toString());
        });
      });
    super.initState();
  }

Sorry for eagerly posting issues. But maybe this helps someone else along the line.

And boys: Read the Readmes more carefully than me, so you don't get this problems. ;)

Btw: Thanks for this plugin!