使用某些插件访问设备通讯录时,应用程序崩溃且没有任何日志

时间:2019-01-04 10:28:52

标签: crash flutter contacts

我想在我尝试使用contacts_servicecontacts_plugin的应用程序中显示联系人,但是在安装软件包后运行它时,应用程序崩溃。我刚刚导入了文件,没有编写任何代码。我也没有看到任何日志。

将联系人集成到我的应用程序中的任何其他方式也将有很大帮助!

2 个答案:

答案 0 :(得分:2)

您确实需要学习和掌握开发Flutter应用程序所需的工具。

当您在SO上发布问题时,您确实确实需要更好地解释您的需求。

那表示我已经快速尝试了contacts_plugincontact_service

请勿同时使用两者,因为它们是出于相同的目的。选择一个。

contact_service似乎更稳定: 92分对82分的加权得分

Android

尝试使用contacts_plugin会遇到这个错误:

* What went wrong:
The Android Gradle plugin supports only Kotlin Gradle plugin version 1.2.51 and higher. Project 'contacts_plugin' is using version 1.2.30.

因为contacts_plugin使用的是kotlin版本1.2.30,并且您的AS> = 3.2像我一样。

ext.kotlin_version = '1.2.30'

如果您想尝试一下,可以克隆该项目并通过以下方式包含依赖项:

contacts_plugin:
    path: ../flutter-contacts-plugin/

并更改插件build.gradle这一行:

ext.kotlin_version = '1.2.30'

与此

ext.kotlin_version = '1.2.51'

如果您使用contact_plugins,即使iOS项目也有问题。

contact_serivce相反,它可以在Android和iOS上正常运行。

无论如何,始终请记住,在Android上,您需要在您的AndroidManifest.xml

中添加此权限
 <uses-permission android:name="android.permission.READ_CONTACTS"/>
 <uses-permission android:name="android.permission.WRITE_CONTACTS"/>

在iOS上,请确保在NSContactsUsageDescription文件中设置Info.plist

<key>NSContactsUsageDescription</key>
<string>This app requires contacts access to function properly.</string>

并在Swift支持下创建Flutter项目。

您可以使用contact_service插件提供的default example开始学习:

import 'package:flutter/material.dart';
import 'package:contacts_service/contacts_service.dart';

void main() => runApp(ContactsExampleApp());

class ContactsExampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(routes: <String, WidgetBuilder>{
      '/add': (BuildContext context) => AddContactPage()
    }, home: ContactListPage());
  }
}

class ContactListPage extends StatefulWidget {
  @override
  _ContactListPageState createState() => _ContactListPageState();
}

class _ContactListPageState extends State<ContactListPage> {
  Iterable<Contact> _contacts;

  @override
  initState() {
    super.initState();
    refreshContacts();
  }

  refreshContacts() async {
    var contacts = await ContactsService.getContacts();
    setState(() {
      _contacts = contacts;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Contacts Plugin Example')),
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: () {
            Navigator.of(context).pushNamed("/add").then((_) {
              refreshContacts();
            });
          }),
      body: SafeArea(
        child: _contacts != null
            ? ListView.builder(
                itemCount: _contacts?.length ?? 0,
                itemBuilder: (BuildContext context, int index) {
                  Contact c = _contacts?.elementAt(index);
                  return ListTile(
                    onTap: () {
                      Navigator.of(context).push(MaterialPageRoute(
                          builder: (BuildContext context) =>
                              ContactDetailsPage(c)));
                    },
                    leading: (c.avatar != null && c.avatar.length > 0)
                        ? CircleAvatar(backgroundImage: MemoryImage(c.avatar))
                        : CircleAvatar(
                            child: Text(c.displayName.length > 1
                                ? c.displayName?.substring(0, 2)
                                : "")),
                    title: Text(c.displayName ?? ""),
                  );
                },
              )
            : Center(child: CircularProgressIndicator()),
      ),
    );
  }
}

class ContactDetailsPage extends StatelessWidget {
  ContactDetailsPage(this._contact);
  final Contact _contact;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar:
            AppBar(title: Text(_contact.displayName ?? ""), actions: <Widget>[
          FlatButton(
              child: Icon(Icons.delete),
              onPressed: () {
                ContactsService.deleteContact(_contact);
              })
        ]),
        body: SafeArea(
          child: ListView(
            children: <Widget>[
              ListTile(
                  title: Text("Name"),
                  trailing: Text(_contact.givenName ?? "")),
              ListTile(
                  title: Text("Middle name"),
                  trailing: Text(_contact.middleName ?? "")),
              ListTile(
                  title: Text("Family name"),
                  trailing: Text(_contact.familyName ?? "")),
              ListTile(
                  title: Text("Prefix"), trailing: Text(_contact.prefix ?? "")),
              ListTile(
                  title: Text("Suffix"), trailing: Text(_contact.suffix ?? "")),
              ListTile(
                  title: Text("Company"),
                  trailing: Text(_contact.company ?? "")),
              ListTile(
                  title: Text("Job"), trailing: Text(_contact.jobTitle ?? "")),
              AddressesTile(_contact.postalAddresses),
              ItemsTile("Phones", _contact.phones),
              ItemsTile("Emails", _contact.emails)
            ],
          ),
        ));
  }
}

class AddressesTile extends StatelessWidget {
  AddressesTile(this._addresses);
  final Iterable<PostalAddress> _addresses;

  Widget build(BuildContext context) {
    return Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          ListTile(title: Text("Addresses")),
          Column(
              children: _addresses
                  .map((a) => Padding(
                        padding: const EdgeInsets.symmetric(horizontal: 16.0),
                        child: Column(
                          children: <Widget>[
                            ListTile(
                                title: Text("Street"),
                                trailing: Text(a.street)),
                            ListTile(
                                title: Text("Postcode"),
                                trailing: Text(a.postcode)),
                            ListTile(
                                title: Text("City"), trailing: Text(a.city)),
                            ListTile(
                                title: Text("Region"),
                                trailing: Text(a.region)),
                            ListTile(
                                title: Text("Country"),
                                trailing: Text(a.country)),
                          ],
                        ),
                      ))
                  .toList())
        ]);
  }
}

class ItemsTile extends StatelessWidget {
  ItemsTile(this._title, this._items);
  final Iterable<Item> _items;
  final String _title;

  @override
  Widget build(BuildContext context) {
    return Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          ListTile(title: Text(_title)),
          Column(
              children: _items
                  .map((i) => Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 16.0),
                      child: ListTile(
                          title: Text(i.label ?? ""),
                          trailing: Text(i.value ?? ""))))
                  .toList())
        ]);
  }
}

class AddContactPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _AddContactPageState();
}

class _AddContactPageState extends State<AddContactPage> {
  Contact contact = Contact();
  PostalAddress address = PostalAddress(label: "Home");
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Add a contact"),
        actions: <Widget>[
          FlatButton(
              onPressed: () {
                _formKey.currentState.save();
                contact.postalAddresses = [address];
                ContactsService.addContact(contact);
                Navigator.of(context).pop();
              },
              child: Icon(Icons.save, color: Colors.white))
        ],
      ),
      body: Container(
        padding: EdgeInsets.all(12.0),
        child: Form(
            key: _formKey,
            child: ListView(
              children: <Widget>[
                TextFormField(
                    decoration: const InputDecoration(labelText: 'First name'),
                    onSaved: (v) => contact.givenName = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Middle name'),
                    onSaved: (v) => contact.middleName = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Last name'),
                    onSaved: (v) => contact.familyName = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Prefix'),
                    onSaved: (v) => contact.prefix = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Suffix'),
                    onSaved: (v) => contact.suffix = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Phone'),
                    onSaved: (v) =>
                        contact.phones = [Item(label: "mobile", value: v)],
                    keyboardType: TextInputType.phone),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'E-mail'),
                    onSaved: (v) =>
                        contact.emails = [Item(label: "work", value: v)],
                    keyboardType: TextInputType.emailAddress),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Company'),
                    onSaved: (v) => contact.company = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Job'),
                    onSaved: (v) => contact.jobTitle = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Street'),
                    onSaved: (v) => address.street = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'City'),
                    onSaved: (v) => address.city = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Region'),
                    onSaved: (v) => address.region = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Postal code'),
                    onSaved: (v) => address.postcode = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Country'),
                    onSaved: (v) => address.country = v),
              ],
            )),
      ),
    );
  }
} 

答案 1 :(得分:0)

感谢您的帮助。我的错误是在其他情况下也使用了联系人选择器。应用程序崩溃,因为我同时使用了联系人选择器和联系人服务。