Приложение падает без каких-либо журналов при использовании некоторых плагинов для доступа к контактам устройства - PullRequest
0 голосов
/ 04 января 2019

Я хочу показать контакты в своем приложении, для которого я пытался использовать contacts_service и contacts_plugin , но мое приложение вылетает при запуске после установки пакетов.Я только что импортировал файл и написал без кода.Также я не вижу никаких журналов.

Любой другой способ интеграции контактов в моем приложении также очень помог бы!

Ответы [ 2 ]

0 голосов
/ 08 января 2019

Спасибо за помощь. Моя ошибка заключалась в использовании средства выбора контактов и для другого сценария. Приложение зависало, потому что я использовал как сборщик контактов, так и службу контактов.

0 голосов
/ 04 января 2019

Вам действительно нужно выучить и освоить инструменты, которые вы должны использовать для разработки приложений Flutter.

И вам действительно нужно лучше объяснить свои потребности при публикации вопроса на SO.

Тем не менее, я быстро попробовал contacts_plugin и contact_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'

Даже у iOS-проекта возникают проблемы, если вы используете contact_plugins.

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>

и создайте проект Flutter с поддержкой Swift.

Вы можете использовать пример по умолчанию ProviПлагин contact_service для начала обучения:

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),
              ],
            )),
      ),
    );
  }
} 
...