GithubHelp home page GithubHelp logo

capacitor-community / contacts Goto Github PK

View Code? Open in Web Editor NEW
115.0 115.0 51.0 871 KB

Contacts Plugin for Capacitor

Home Page: https://capacitor-community.github.io/contacts/

Ruby 1.00% Java 56.59% Objective-C 1.14% Swift 32.84% JavaScript 0.56% TypeScript 7.74% Shell 0.12%

contacts's People

Contributors

allcontributors[bot] avatar danieltech99 avatar david-garzon-adl avatar dependabot[bot] avatar dotnetkow avatar idrimi avatar mlynch avatar muuvmuuv avatar rdlabo avatar reslear avatar tafelnl avatar trinitiwowka avatar vhinic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

contacts's Issues

Ionic 5 + Vue 3 Support

Describe the bug
I am trying to use this plugin with Ionic 5 + Vue 3 since the Cordova Contact plugin seems to be deprecated however, I am unable to get it to work and I am unable to find any documentation related to Ionic 5 + Vue 3 + Capactor plugins that works. If you have any insight, I would appreciate it.

To Reproduce
The code below is what I have tried. Essentially, there's a button that calls "chooseContacts" but nothing happens and the iOS console log simply shows "error" and nothing else.

<script>
import { defineComponent } from 'vue';
import { Plugins } from '@capacitor/core'

export default defineComponent({
  mounted() {
    this.contacts = Plugins
  },
  methods: {
    chooseContacts() {
      this.contacts.getContacts().then(results => {
        console.log(results)
      })
    }
  }
});
</script>

Expected behavior
I am expecting the console log to show a list of contacts as the result.

Screenshots
NA

Desktop (please complete the following information):

  • OS: MacOS 10.15.7
  • Browser: NA
  • Version: NA

Smartphone (please complete the following information):

  • Device: iOS Simulator
  • OS: iOS 14.?
  • Browser: NA
  • Version: NA

Pick Contact

Describe the solution you'd like
I wonder if it would possible to have a method inside the plugin to pick a single contact by using the OS native UI as the Cordova deprecated plugin did through the method pickContact.

Describe alternatives you've considered

Additional context

feat: add ability to save image on `createContact`

Documentation and typescript mention that method saveContact has image parameter, and that you can set contact image. However native code (android and iOS) has no such feature.

Parameter 'image', passed in TypeScript angular application, is never red in the saveContact native methods.

Save to contacts

Is your feature request related to a problem? Please describe.

Our customers are manually creating leads (contacts) in our app, and we would like to let the user have the option to save that lead into their phone's contacts.

Describe the solution you'd like

Camera.saveContact()

Describe alternatives you've considered

/

Additional context

With some direction and help, we would contribute that feature by ourselves.

checkPermissions doesn't give back a response on iOS

Describe the bug
I have updated the plugin from v2.0.0 to v4.0.0. While testing on both platforms, I have noticed that the checkPermissions() method doesn't do anything on iOS. Well, at least the native code is called, but I never received a response.

To Reproduce
Steps to reproduce the behavior:

  1. Install the latest version of the plugin (v4)
  2. Try to call the checkPermissions() method on iOS

Expected behavior
I should get a response from the method saying if it's granted, denied, etc...

Screenshots
Logs on iOS:

Logs

The response is missing.

Android for example, works correctly, see logs as a demonstration of the expected behavior:

Logs

Smartphone:

  • Device: iPhone 14 Emulator
  • OS: 16.2

Additional context
None so far.

Some contact fields are missing even though they are present on the contact card

Describe the bug
When loading in contacts, some of their already present fields are missing. Fields such as birthday date are returned undefined, even though the contact has that saved on the contact card.

This is happening for many contacts.

To Reproduce
Steps to reproduce the behavior:

  1. Just load contacts

Expected behavior
To see all fields present on the contact card.

Screenshots
If applicable, add screenshots to help explain your problem.
IMG_54CC39CC3832-1
Group

Smartphone (please complete the following information):

  • Device: iPhone XS
  • OS: iOS 13.5

(feature) Write Contact

There is no mention of writing a contact in Readme and typescript didn't give me any clues.

Readme, however, mentions writing in Android permissions.

Thank you.

Contacts.getPermissions on android - unexpected first call result

Describe the bug

Hello.
On android Contacts.getPermissions returns object with a shape {"contacts": "granted" } instead of { granted: true } on first call(e.g. when user did not give the permissions yet), but { granted: true } on the subsequent calls.
I believe that the root of evil is here, and it looks like #40 is going to fix it.

To Reproduce

  1. Call Contacts.getPermissions() on android without granted or denied permissions
  2. Check the output
import { Contacts } from "@capacitor-community/contacts";
const perm = await Contacts.getPermissions();

Expected behavior

Should always return { granted: true|false }

Screenshots

Screenshot_20211116_131326
Screenshot_20211116_131343

Smartphone (please complete the following information):

  • OS: Android 11

Can you still request permissions on v4 Android?

Describe the bug
The docs say there's a requestPermissions() method, but I can't seem to see a PluginMethod in the android source for this method? I was looking for it to be sure of what the behavior was as we're migrating from the old @ionic-native/contacts plugin

I'm using Capacitor 4, and therefore v4-beta of this package

REQUEST_CODE used is too generic, which causes conflicts with Cordova Fingerprint plugin in ANDROID

Describe the bug
The contacts plugin define request code as 1, but the FingerPrint Cordova plugin also uses this code, so If in my project I have both plugins, then the Fingerprint will fail, because it delegates the onResult android method to our plugin, is there any chance to change the request code?

To Reproduce
Steps to reproduce the behavior:

  1. Install Cordova FingerPrint plugin
  2. Install Contacts plugin
  3. Try to autenticates using fingerprint

Expected behavior
Both plugins should work together.

Android permissions issues causing app crash

Describe the bug

When request permissions using Contacts.getPermissions() the app works on iOS but crashes immediately on Android.

To Reproduce
Steps to reproduce the behavior:

  1. Execute following commands: npx cap copy;npx cap sync;ionic cap sync;ionic cap copy android;npx cap open android
  2. Launched Android Simulator (Pixel 3a API 30 x86)
  3. Execute Contacts.getPermissions()

At this point, the app crashes though the permissions request dialog does popup.

Expected behavior

Request permissions dialog is presented over the running app, Allow is clicked, contacts are retreived and the Ionic select picker is presented with the list of contacts.

Screenshots

Can provide a video, if it would help.

Desktop (please complete the following information):

  • OS: MacOS 10.15.7
  • Browser: NA
  • Version: MacOS 10.15.7

Smartphone (please complete the following information):

  • Device: Android Pixel 3a
  • OS: Android 10+ (API 30)
  • Browser: NA
  • Version: 10+ (API 30)

Additional context

I have added the required entries to the AndroidManifest but the app crashes when asking for permissions to contacts. A confirmation dialog would popup asking the user to allow access to the contacts but the app would crash immediately.

2021-01-21 23:15:55.285 10056-10486/com.puretrim.app E/Capacitor: Serious error executing plugin
    java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:99)
        at com.getcapacitor.Bridge$1.run(Bridge.java:542)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.os.HandlerThread.run(HandlerThread.java:67)
     Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord{93554ff 10056:com.puretrim.app/u0a157} (pid=10056, uid=10157) requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS
        at android.os.Parcel.createExceptionOrNull(Parcel.java:2373)
        at android.os.Parcel.createException(Parcel.java:2357)
        at android.os.Parcel.readException(Parcel.java:2340)
        at android.os.Parcel.readException(Parcel.java:2282)
        at android.app.IActivityManager$Stub$Proxy.getContentProvider(IActivityManager.java:5702)
        at android.app.ActivityThread.acquireProvider(ActivityThread.java:6813)
        at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2930)
        at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:2481)
        at android.content.ContentResolver.query(ContentResolver.java:1167)
        at android.content.ContentResolver.query(ContentResolver.java:1115)
        at android.content.ContentResolver.query(ContentResolver.java:1071)
        at ch.byrds.capacitor.contacts.Contacts.getContacts(Contacts.java:99)
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:99) 
        at com.getcapacitor.Bridge$1.run(Bridge.java:542) 
        at android.os.Handler.handleCallback(Handler.java:938) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.os.HandlerThread.run(HandlerThread.java:67) 
     Caused by: android.os.RemoteException: Remote stack trace:
        at com.android.server.am.ActivityManagerService.getContentProviderImpl(ActivityManagerService.java:7129)
        at com.android.server.am.ActivityManagerService.getContentProvider(ActivityManagerService.java:7568)
        at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2381)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2861)
        at android.os.Binder.execTransactInternal(Binder.java:1154)
2021-01-21 23:15:55.290 10056-10056/com.puretrim.app D/Capacitor: App paused
2021-01-21 23:15:55.296 10056-10486/com.puretrim.app E/AndroidRuntime: FATAL EXCEPTION: CapacitorPlugins
    Process: com.puretrim.app, PID: 10056
    java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
        at com.getcapacitor.Bridge$1.run(Bridge.java:551)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.os.HandlerThread.run(HandlerThread.java:67)
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:99)
        at com.getcapacitor.Bridge$1.run(Bridge.java:542)
        at android.os.Handler.handleCallback(Handler.java:938) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.os.HandlerThread.run(HandlerThread.java:67) 
     Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord{93554ff 10056:com.puretrim.app/u0a157} (pid=10056, uid=10157) requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS
        at android.os.Parcel.createExceptionOrNull(Parcel.java:2373)
        at android.os.Parcel.createException(Parcel.java:2357)
        at android.os.Parcel.readException(Parcel.java:2340)
        at android.os.Parcel.readException(Parcel.java:2282)
        at android.app.IActivityManager$Stub$Proxy.getContentProvider(IActivityManager.java:5702)
        at android.app.ActivityThread.acquireProvider(ActivityThread.java:6813)
        at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2930)
        at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:2481)
        at android.content.ContentResolver.query(ContentResolver.java:1167)
        at android.content.ContentResolver.query(ContentResolver.java:1115)
        at android.content.ContentResolver.query(ContentResolver.java:1071)
        at ch.byrds.capacitor.contacts.Contacts.getContacts(Contacts.java:99)
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:99) 
        at com.getcapacitor.Bridge$1.run(Bridge.java:542) 
        at android.os.Handler.handleCallback(Handler.java:938) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.os.HandlerThread.run(HandlerThread.java:67) 
     Caused by: android.os.RemoteException: Remote stack trace:
        at com.android.server.am.ActivityManagerService.getContentProviderImpl(ActivityManagerService.java:7129)
        at com.android.server.am.ActivityManagerService.getContentProvider(ActivityManagerService.java:7568)
        at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2381)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2861)
        at android.os.Binder.execTransactInternal(Binder.java:1154)
2021-01-21 23:15:55.363 10056-10486/com.puretrim.app I/Process: Sending signal. PID: 10056 SIG: 9

If I manually give the app Contacts permissions, nothing happens. The app does not crash nor does it actually trigger the API to grab the contacts.

Here is the code:

    async doSelectContact() {
      const { Contacts } = Plugins;

      Contacts.getPermissions()

      this.picker.buttons = [
        {
          text: 'Cancel',
          role: 'cancel'
        },
        {
          text: 'Confirm',
          handler: (value) => {
            this.doAddContact(value)
          }
        }
      ]

      if (this.contacts.length <= 0) {
        await Contacts.getContacts().then(async (contacts) => {
          await contacts.contacts.forEach(contact => {
            if (contact.phoneNumbers.length >= 1) {
              this.contacts.push({
                text: contact.displayName,
                value: contact.phoneNumbers[0]
              })
            }

            this.picker.columns = [{
              name: 'Contacts',
              options: this.contacts
            }]

            this.picker.open = true
          })
        });
      }
    },

Contact Photos in Result

Is your feature request related to a problem? Please describe.
n/a

Describe the solution you'd like
An array of linked contact photos in the result.

Describe alternatives you've considered
The main contact photo as string.

Additional context
n/a

projection is returning more fields than expected

Describe the bug
According to the docs here, if we use:

const {contacts} = await Contacts.getContacts({
      projection: {
        name: true // <======
      }
    });

It will only return two properties: contactId and name. This is not what is happening, I am receiving more fields, phones.

Example:

[
    {
        "contactId": "1",
        "name": {
            "display": "Juan Perez",
            "given": "Juan",
            "family": "Perez"
        },
        "phones": [
            {
                "type": "mobile",
                "number": "(809) 333-2222"
            },
            {
                "type": "custom",
                "label": "Flote",
                "number": "(849) 333-2222"
            }
        ]
    },
]

The same thing is happening with the pickContact() method. Example:

const result = await Contacts.pickContact({
      projection: {
        name: true
      }
});

Platforms

  • Android

iOS seems to be fine, but maybe you can re-validate the issue on iOS to be sure is not happening.

To Reproduce
Steps to reproduce the behavior:

  1. Install the latest version of the plugin
  2. Call getContacts() method with a projection with only name
  3. Call pickContact() method with a projection with only name

Expected behavior
Contacts should have only a name object, no more than that.

Example:

[
    {
        "contactId": "1",
        "name": {
            "display": "Juan Perez",
            "given": "Juan",
            "family": "Perez"
        },
    },
]

Screenshots
None.

Smartphone (please complete the following information):

  • Device: Android Emulator Nexus 6
  • OS: API 31 Android 12

Additional context
None.

Property which is showing if user already granted contact permission

@capacitor-community/contacts : "^1.0.9"
@capacitor/core: "^3.3.2",

I m using Contacts plugin to access user phone contacts. It needs to call Contacts.getPermissions() function to grant access. If user already granted this permission, i don't want to call getPermissions() function again.

Is there any variable which keep a state of current device if it already granted access ?

Have to sync gradle first before import can be resolved

I followed all the steps in the docs.
But when importing the Contacts class like described in the docs:
import ch.byrds.capacitor.contacts.Contacts;

I received the following error: Cannot resolve symbol ch

As a solution I added an extra random character to the gradle file and clicked the sync button that then appears
image

Then I removed the random character and synced again.

This made the error disappear.

I am not sure if this is an error with Capacitor itself (i tried running cap update, cap sync and cap copy but none helped) or something else

Missing NPM v1.0.8 Package

Cannot install v1.0.8.

I need to install this version via npm to support Capacitor 2, but getting an error that this package does not exist.

Could this be a Bug?

Describe the bug
Could this be a Bug?

Expected behavior
I shouldn't be getting any errors.

Screenshots
issue

Desktop (please complete the following information):

  • OS: Windows 11
  • Android Studio
  • Version Android Studio Arctic Fox | 2020.3.1 Patch 4

Smartphone (please complete the following information):

  • Device: Samsung
  • OS: Android

Additional context
none

Add support for Capacitor 4

Describe the bug
When upgrading from Capacitor 3 to Capacitor 4, npm install fails with the message:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: [email protected]
npm ERR! Found: @capacitor/[email protected]
npm ERR! node_modules/@capacitor/core
npm ERR!   @capacitor/core@"4.0.1" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer @capacitor/core@"^3.0.0" from @capacitor-community/[email protected]
npm ERR! node_modules/@capacitor-community/contacts
npm ERR!   @capacitor-community/contacts@"^1.1.3" from the root project

To Reproduce
Steps to reproduce the behavior:

  1. Upgrade to Capacitor 4
  2. Install this plugin

Expected behavior
Install should not return any dependency error.

Additional context
Capacitor 4 has been released recently, see releases here. The peerDependencies of this plugin need an update.

build output error

i used this code in my angular project then i convert my project into capacitor then i use this npm and run code in android studio then adroid throws error error: cannot find symbol
this.init(savedInstanceState, new ArrayList<Class<? extends Plugin>>() {{
^
symbol: method init(Bundle,<anonymous ArrayList<Class<? extends Plugin>>>)

my java main activity code is package flycard.app;
import ch.byrds.capacitor.contacts.Contacts;
import android.os.Bundle;

import com.getcapacitor.BridgeActivity;
import com.getcapacitor.Plugin;
import java.util.ArrayList;

public class MainActivity extends BridgeActivity {
@OverRide
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// Initializes the Bridge
this.init(savedInstanceState, new ArrayList<Class<? extends Plugin>>() {{
// Additional plugins you've installed go here
// Ex: add(TotallyAwesomePlugin.class);
add(Contacts.class);
}});
}
}

(Save Contact) support android types of email, phone, address and save website

When saving a contact that contains emails, phone numbers, or addresses, the contact is saved with a custom type and not with android's own constants, for example TYPE_HOME, TYPE_WORK, etc.

In addition to this, if a website is sent, the information is not saved and in the case of the address it assumes that street, city, state, zip code, country is sent.

Given this, I made changes to the Contacts.java file that allows you to save the contact information in a better way, I hope it will help you. I show places where I made the changes:

  • Contacts.java

`import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import com.getcapacitor.JSArray;
import com.getcapacitor.JSObject;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.getcapacitor.annotation.Permission;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public void saveContact(PluginCall call) throws JSONException {
// TODO: allow more than these three email types
if (emailAddresses.size() > 0) {
JSObject primaryEmail = JSObject.fromJSONObject((JSONObject) emailAddresses.get(0));
intent.putExtra(ContactsContract.Intents.Insert.EMAIL, primaryEmail.getString("address", ""));
intent.putExtra(ContactsContract.Intents.Insert.EMAIL_TYPE, primaryEmail.getInteger("label", Email.TYPE_HOME));
intent.putExtra(ContactsContract.Intents.Insert.EMAIL_ISPRIMARY, true);

        if (emailAddresses.size() > 1) {
            JSObject secondaryEmail = JSObject.fromJSONObject((JSONObject) emailAddresses.get(1));
            intent.putExtra(ContactsContract.Intents.Insert.SECONDARY_EMAIL, secondaryEmail.getString("address", ""));
            intent.putExtra(ContactsContract.Intents.Insert.SECONDARY_EMAIL_TYPE, secondaryEmail.getInteger("label", Email.TYPE_HOME));

            if (emailAddresses.size() > 2) {
                JSObject tertiaryEmail = JSObject.fromJSONObject((JSONObject) emailAddresses.get(2));
                intent.putExtra(ContactsContract.Intents.Insert.TERTIARY_EMAIL, tertiaryEmail.getString("address", ""));
                intent.putExtra(ContactsContract.Intents.Insert.TERTIARY_EMAIL_TYPE, tertiaryEmail.getInteger("label", Email.TYPE_HOME));
            }
        }
    }

// TODO: allow more than these three phone number types
if (phoneNumbers.size() > 0) {
JSObject primaryNumber = JSObject.fromJSONObject((JSONObject) phoneNumbers.get(0));
intent.putExtra(ContactsContract.Intents.Insert.PHONE, primaryNumber.getString("number", ""));
intent.putExtra(ContactsContract.Intents.Insert.PHONE_TYPE, primaryNumber.getInteger("label", Phone.TYPE_HOME));
intent.putExtra(ContactsContract.Intents.Insert.PHONE_ISPRIMARY, true);

        if (phoneNumbers.size() > 1) {
            JSObject secondaryNumber = JSObject.fromJSONObject((JSONObject) phoneNumbers.get(1));
            intent.putExtra(ContactsContract.Intents.Insert.SECONDARY_PHONE, secondaryNumber.getString("number", ""));
            intent.putExtra(ContactsContract.Intents.Insert.SECONDARY_PHONE_TYPE, secondaryNumber.getInteger("label", Phone.TYPE_HOME));

            if (phoneNumbers.size() > 2) {
                JSObject tertiaryNumber = JSObject.fromJSONObject((JSONObject) phoneNumbers.get(2));
                intent.putExtra(ContactsContract.Intents.Insert.TERTIARY_PHONE, tertiaryNumber.getString("number", ""));
                intent.putExtra(ContactsContract.Intents.Insert.TERTIARY_PHONE_TYPE, tertiaryNumber.getInteger("label", Phone.TYPE_HOME));
            }
        }
    }

    // TODO: allow more than one address
    if (addresses.size() > 0) {
        JSObject address = JSObject.fromJSONObject((JSONObject) addresses.get(0));
        JSObject postalObject = address.getJSObject("address", new JSObject());
        ArrayList<String> postalArray = new ArrayList<String>();
        postalArray.add(postalObject.getString("street", ""));
        postalArray.add(postalObject.getString("city", ""));
        postalArray.add(postalObject.getString("state", ""));
        postalArray.add(postalObject.getString("postalCode", ""));
        postalArray.add(postalObject.getString("country", ""));
        postalArray.removeAll(Arrays.asList("", null));
        String postal = TextUtils.join(", ", postalArray);
        intent.putExtra(ContactsContract.Intents.Insert.POSTAL, postal);
        intent.putExtra(ContactsContract.Intents.Insert.POSTAL_TYPE, address.getInteger("label", StructuredPostal.TYPE_HOME));
        intent.putExtra(ContactsContract.Intents.Insert.POSTAL_ISPRIMARY, true);
    }

    // UrlAddresses

  JSArray urlAddressesArray = call.getArray("urlAddresses", new JSArray());
  List<Object> urlAddresses = urlAddressesArray.toList();

  if (urlAddresses.size() > 0) {
    ArrayList<ContentValues> data = new ArrayList<ContentValues>();
    ContentValues rowUrlAddress = new ContentValues();
    JSObject urlAddress = JSObject.fromJSONObject((JSONObject) urlAddresses.get(0));
    rowUrlAddress.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE);
    rowUrlAddress.put(ContactsContract.CommonDataKinds.Website.URL, urlAddress.getString("url", ""));
    rowUrlAddress.put(ContactsContract.CommonDataKinds.Website.TYPE, urlAddress.getInteger("label", Website.TYPE_HOME));
    data.add(rowUrlAddress);
    intent.putExtra(ContactsContract.Intents.Insert.DATA, data);
  }

}`

  • contacts\dist\esm\definitios.ts

export interface PhoneNumber { label?: number; number?: string; } export interface EmailAddress { label?: number; address?: string; } export interface PostalAddress { label?: number; address?: { street?: string; city?: string; state?: string; postalCode?: string; country?: string; }; }

Result with the changes applied in Contacts.java:

Screenshot_20220211_181809
Screenshot_20220211_181844

Missing middleName in displayName on IOS

Describe the bug

The plugin does not add middleName in contact displayName

To Reproduce
Steps to reproduce the behavior:

  1. Create new capacitor project
  2. Add this plugin
  3. Fetch contact list and display diaplayName
  4. You will see the displayName does not include middleName for contacts where it exists

Expected behavior
The displayName should includegivenName,middleName, and famillyName

Screenshots

Desktop (please complete the following information):

Smartphone (please complete the following information):

  • Device: iPhone12
  • OS: iOS14.2
  • Browser safari

Additional context
Change line 68 in Plugin.swift to "displayName": "\(contact.givenName) \(contact.middleName) \(contact.familyName)", should fix the issue.

Get Physical Address

There is a way to input the physical address of contact. However, according to the Interface there is no way to retrieve it.

Describe the solution you'd like
Add Address with an Address Interface

Describe alternatives you've considered
There is no alternative

Add Phone Number Labels

Is your feature request related to a problem? Please describe.
I have used the Cordova Contacts plugin for many years and original underestimated how important the labels are for phone numbers. Without them, very little context is offered.

Describe the solution you'd like
I am very novice in swift but managed to add labels to the phoneNumbers array returned from getContacts in iOS with

for number in contact.phoneNumbers {
     let numberToAppend = number.value.stringValue
     let labelToAppend = number.label?.replacingOccurrences(of: "[!$_<>]", with: "", options: .regularExpression, range: nil)
     phoneNumbers[labelToAppend] = numberToAppend                      
 }

That might be horrible practice in Swift but it's working for me.

Describe alternatives you've considered
Without adding the label to each phone number it will be very difficult to know which number needs to be selected in an app using this plugin.

Capacitor 3 Support

Is your feature request related to a problem? Please describe.

The Capacitor 3 RC is out! ๐ŸŽ‰ This library should support the new version

Describe the solution you'd like

Follow the plugin upgrade guide here: https://capacitorjs.com/docs/v3/updating/plugins/3-0

Additional context

The migration is pretty easy, I've done it for a couple plugins. Happy to assist if you need assisting!

Accessing contact creation date

Hi, I'm the founder of FriendApp. Thank you for your great work on this component.

I was wondering if the import process could also read the contact creation date for iPhone and Android? We're going through a lengthy workaround to detect new contacts added by users, and was curious to see if there might be an easier way to handle this is we could read the iphone and Android contact creation date.

Please feel free to download if you'd like to check out our app :)
https://apps.apple.com/us/app/friend/id1599335622

RFC: support for updating a contact

Updating a contact may be considered a fairly basic feature that should probably be implemented. However, it is not as straight forward as one might think.


If you are in need of this functionality, please +1 this post by means of a GitHub reaction (so not with a comment).


Approach 1

The easiest approach would be to implement a PUT instead of PATCH (REST-API analogy). That means that the contact will get completely overwritten with the newly defined values. Essentially, this would be the same as removing the contact and creating a new one.

This is quite easy to implement, but the developer experience, and (maybe moreover) the user experience is sub-optimal to say the least.

If the developer only wants to update a single contact's phone number, he would still have to retrieve all of that user's data, and consequently put all that data into the updateContact method. Not very ideal.

If the developer forgets to do above said things, a user might end up with a contact with only the newly updated phone number, with all "old" data deleted. Not very user friendly.


Approach 2

It would be possible to do a "partial PUT". This would entail that the developer does not have to supply all data, but just the data for the object he is updating. So if, for example, the developer wants to update a contact's phone number, he will only have to supply all the other phone numbers that are supposed to be kept.

This approach has a better developer experience than approach # 1, but it's still not very ideal.


Approach 3

Arguably the best approach is this: make it possible to retrieve the IDs of a contact's phone, email, postal address etc. This way a developer can just specify which object (phone, email, postal address) object should be updated, by simply providing the correct id.

Still this has some quirks that should be thought about. For example:

The developer wants to updated the postal address with id 123. But he only wants to update the street, not all the other fields... What should be done now? Does the developer have to specify all the other "old" fields, so we can overwrite the whole object. Or does the API only update the given fields. But in the latter case, how would it be possible to delete / empty fields?

Of course, this approach, will also take the longest to develop and test.


All in all, still some questions. Unfortunately, I don't have the time, nor the need, to implement this. But of course, suggestions, comments, PRs, or any input for that matter, is very welcome.

Which plugin is being maintained @capacitor-community/contacts or @byrds/capacitor-contacts?

Describe the bug
This plugin @capacitor-community/contacts crashes on Android so I tried the referenced demo app in the README and it does NOT crash. However, the demo app uses a different plug-in @byrds/capacitor-contacts.

Is the source code for these plugins supposed to be identical? I'm confused why both exist and why the one under "capacitor-community" is the one that is crashing. It's also confusing that this plugin points to a demo app at the uses a different plugin.

Android app crash on Deny permission

Describe the bug
App crash on "Deny" permission selection (Android only)

To Reproduce
Steps to reproduce the behavior:

  1. Request permission prompt
  2. Tap 'Deny'

Expected behavior
Catch the failure internally and return { granted: false } from Contacts.getPermissions()

Smartphone (please complete the following information):

  • Device: Samsung Note 9
  • OS: Android 10
  • Browser: stock browser

Additional context
AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_PROFILE" android:maxSdkVersion="29" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" />

Performance of getContacts() (Android)

I have not tested on iOS but Android performance seems to be lacking.

Loading of ~500 contacts takes ~20 to ~30 seconds on a Samsung Galaxy S10.

I am in no way an Android expert. I have very little experience with Android development. But I was able to build a little ContactsPlugin.java class based on stackoverflow sources. And this works way faster (< 1 second). However it does not handle birthday etc. But it does the core job of getting names and phone numbers.

import android.content.ContentResolver;
import android.database.Cursor;

import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.util.Log;

import com.getcapacitor.JSArray;
import com.getcapacitor.JSObject;
import com.getcapacitor.NativePlugin;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;

import java.util.HashSet;
import java.util.Set;

@NativePlugin()
public class ContactsPlugin extends Plugin {

    private static String TAG = "CONTACT";

    // Get contacts
    // Output example:
    // { contacts: [{ fullname: 'John Doe', phone: '+31612345678' }] }
    @PluginMethod()
    public void getContacts(PluginCall call) {

        JSArray contacts = new JSArray();
        Set<String> uniquePhonenumbers = new HashSet<String>();

        ContentResolver contentResolver = getContext().getContentResolver();
        Cursor phoneCursor = contentResolver.query(Phone.CONTENT_URI, new String[]{Phone._ID, Phone.DISPLAY_NAME, Phone.NUMBER}, null, null, Phone.DISPLAY_NAME + " ASC");

        if (phoneCursor != null && phoneCursor.getCount() > 0) {
            while (phoneCursor.moveToNext()) {
                String fullname = phoneCursor.getString(phoneCursor.getColumnIndex(Phone.DISPLAY_NAME));
                String phone = phoneCursor.getString(phoneCursor.getColumnIndex(Phone.NUMBER));
                if (phone != null && !phone.isEmpty()) {
                    // remove whitespaces from phone number
                    // this way we can check for duplicates more accurately
                    String phoneStripped = phone.replaceAll("\\s+", "");
                    // check for duplicates
                    if (!uniquePhonenumbers.contains(phoneStripped)) {
                        JSObject obj = new JSObject();
                        obj.put("fullname", fullname);
                        obj.put("phone", phone);
                        contacts.put(obj);
                        // put in hashlist to be able to check for duplicates
                        uniquePhonenumbers.add(phoneStripped);
                        Log.d(TAG, "phone:" + phone);
                    }
                }
            }
        }

        JSObject obj = new JSObject();
        obj.put("contacts", contacts);

        call.resolve(obj);
    }

}

Business Name

Is your feature request related to a problem? Please describe.

On iOS devices, if the contact has a phone number and a business name but no first or last name, the contact returned is simply the phone number. When displaying this information on a contact list selector, it makes for a bad user experience.

Example JSON key value pair object:

      {
         "phoneNumbers":[
            "(000) 000-0000"
         ],
         "contactId":"6AA19AB6-16CF-4325-9E3B-5EDF948AC577:ABPerson",
         "displayName":" ",
         "emails":[
            
         ]
      }

Describe the solution you'd like

It would be nice of the business name was returned in the object. The documentation says "organizationName" should exist however, using version 0.1.1 of the plugin, I do not see this key value pair, even empty.

Describe alternatives you've considered

For now, we're going to filter out phone numbers that do not have a first and / or last name.

Using this module from the window.Capacitor.plugins variable

Once installed, Contact plugin is not available in the "window.Capacitor.Plugins" javascript variable, as all the Core plugins are.

I don't use any bundler, so I can't use the "import" usage recommandation.

How to use this capacitor plugin without import, and like other plugins (for example window.Capacitor.Plugins.SplashScreen.hide()

Thanks

Missing birthday, organizationName and organizationRole on iOS

Describe the bug
When running on iOS birthday, organizationName and organizationName are not populated in returned contacts structure.

To Reproduce
Steps to reproduce the behavior:

  1. On iOS call Contacts.getContacts()
  2. Observe returned contacts array and notice that birthday, organizationName and organizationName are missing.

Expected behavior
Expecting to have birthday, organizationName and organizationName populated for contacts that have birthday and organization/copany in native contacts app - same as on Android.

Failing to compile Plugin.swift

Describe the bug

A clear and concise description of what the bug is.

After installing the plugin with npm and syncing with capacitor I'm unable to compile my project in xcode.

The following errors are thrown in the Plugin.swift file:

  • Invalid conversion from throwing function of type '(Bool) throws -> Void' to non-throwing function type '(Bool) -> Void' Line 34
  • Consecutive statements on a line must be separated by ';' Line 87
  • Expected expression Line 87
  • Expected '}' in class Line 98

To Reproduce
Steps to reproduce the behavior:

  1. npm i --save @capacitor-community/contacts
  2. npx cap sync
  3. build in xcode

Expected behavior

A clear and concise description of what you expected to happen.

I expect it to build.

Screenshots

If applicable, add screenshots to help explain your problem.

Screen Shot 2021-02-02 at 8 01 29 PM

Screen Shot 2021-02-02 at 8 01 39 PM

Desktop (please complete the following information):

  • OS: macOS Catalina v10.15.5
  • Xcode: 12.4 (12D4e)

Smartphone (please complete the following information):

  • Device: iPhone 12 Pro Max
  • OS: iOS v14.3
  • Ionic: v5
  • Capacitor: v2.4.4
  • Plugin Version: v0.1.0

Update a contact in the address book

Describe the bug
I have read the contacts from the address book in my app. Now, if few changes are made to the contact then is it possible to update the existing contact in the address book?

There is only save method which i understand will just create a new contact rather updating.

Please advise

No podspec found for `CapacitorCommunityContacts`

capacitor 3

โœ– Updating iOS native dependencies with pod install - failed!
โœ– update ios - failed!
[error] Analyzing dependencies
[!] No podspec found for CapacitorCommunityContacts in ../../node_modules/@capacitor-community/contacts

Ability to delete contact

Is your feature request related to a problem? Please describe.
It seems there is no way to delete the contact.

Describe the solution you'd like
I would like to have the ability to delete the contact from address book so that my app can help user keep the address book clean as well.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Extra whitespace is being added in contact name on saveContact()

Extra whitespace is being added in contact name on saveContact()
I tested this with android , extra whitespace is being added in contact name at end.
I think problem is : I am passing only givenName and in plugin I can see there is middle and family name is being concatenated,
so if no value is given for middle and family name it takes 2 whitespaces at end.

To Reproduce
Steps to reproduce the behavior:

  1. Create blank ionic project
  2. install capacitor-community/contacts plugin
  3. save contact using Contact.saveContact() method only pass givenName parameter

Expected behavior
Should not add extra spaces in name

Screenshots
WhatsApp Image 2022-04-20 at 7 14 26 PM

Contacts for PWA using javascript || jquery

I apologise in advance for writing this here, i could find a link to contact the developer direct.

How would i get this contacts plugin to work on a PWA using JavaScript or jQuery ? and is this possible? I'm busy learning about Capacitor. I have searched for days now, but not finding any conclusive information. Hence I'm writing here. A example would would also be appreciated. Greets Tony

add sort capabilties

Describe the solution you'd like
Getting the contacts sorted by user system preferences is very helpful. it could also be based on a data passed to the plugin call (sort order asc / dec etc..)

Additional context
on android all you have to do is add sortOrder to the query (this gives the same sort order as default contacts app):

 String sortOrder = ContactsContract.Contacts.SORT_KEY_PRIMARY + " ASC";
        Cursor contactsCursor = contentResolver.query(ContactsContract.Data.CONTENT_URI, projection, selection, selectionArgs, sortOrder);

on ios my implementation is different, here is how I get the contacts and sort them:

//
// ContactsPlugin.swift
// App
//
// Created by Guy Kedar on 2/27/20.
//

import Foundation
import Contacts
import Capacitor

let encoder = JSONEncoder()

var contactsStore: CNContactStore = CNContactStore();

@objc(ContactsPlugin)
public class ContactsPlugin: CAPPlugin {

@objc func authorize(_ call: CAPPluginCall) {
    
    // Check if contacts is available
    contactsStore.requestAccess(for: .contacts) {(access, error) in
        if !access {
            call.reject("Could not get contacts read permission")
        }
        call.resolve()
        
    }
    
    // Request permission
    
}
    @objc func getContacts(_ call: CAPPluginCall){
        
        let req = CNContactFetchRequest(keysToFetch: [
            CNContactFamilyNameKey as CNKeyDescriptor,
            CNContactGivenNameKey as CNKeyDescriptor,
            CNContactPhoneNumbersKey as CNKeyDescriptor,
            CNContactThumbnailImageDataKey as CNKeyDescriptor,
            CNContactImageDataAvailableKey as CNKeyDescriptor,
            CNContactIdentifierKey as CNKeyDescriptor
        ])
        
        req.sortOrder = CNContactSortOrder.userDefault
        
        var contacts: [[String: Any]]  = [];
        try! contactsStore.enumerateContacts(with: req) {
            contact, stop in
            if (!contact.phoneNumbers.isEmpty) {
                var numbers: [String] = []
                for phoneNumber in contact.phoneNumbers {
                    numbers.append(phoneNumber.value.stringValue)
                }
                
                
                var customContact: [String: Any] = ["displayName": contact.givenName + " " + contact.familyName, "phoneNumbers": numbers, "contactId": contact.identifier
                ]
                if (contact.imageDataAvailable) {
                    customContact["image"] = contact.thumbnailImageData?.base64EncodedString()
                }
                
                contacts.append(customContact)
            }
            
        }
        print("## after contacts", contacts.count)
        call.resolve([
            "contacts": contacts
        ])
        
        
    }
}

I am no Java or swift expert, just hacking around using stack overflow but will be happy to contribute.

P.S thanks for this plugin, I had serious perf problems with android and managed to cut read times from 20sec to 200ms by using code from here.

I think generally adding sort and more optional fields like contact images could make this plugin more generic and useful.

projection with image crashes the App on iOS

Describe the bug
Using the plugin v4.0.1 (latest), the app crashes on iOS if I use a projection with image.

To Reproduce
Steps to reproduce the behavior:

const {contacts} = await Contacts.getContacts({
      projection: {
        name: true,
        phones: true,
        image: true // <=====
      }
});
console.log(contacts);

Expected behavior
No crashes.

Screenshots
Crash

Smartphone (please complete the following information):

  • Device: iPhone 14 Emulator
  • OS: 16.2

Xcode logs
I don't know if these logs can give you more insight of the issue.

"exception" : {"codes":"0x0000000000000000, 0x0000000000000000","rawCodes":[0,0],"type":"EXC_CRASH","signal":"SIGABRT"},
"asiBacktraces" : ["0   CoreFoundation                      0x000000018040e7c8 __exceptionPreprocess + 172\n1   libobjc.A.dylib                     0x0000000180051144 objc_exception_throw + 56\n2   CoreFoundation                      0x000000018040e6d8 -[NSException initWithCoder:] + 0\n3   Contacts                            0x000000018871ffe4 -[CNContact thumbnailImageData] + 144\n4   CapacitorCommunityContacts          0x00000001027d6780 $s26CapacitorCommunityContacts14ContactPayloadC8fillDatayySo9CNContactCF + 5692\n5   CapacitorCommunityContacts          0x00000001027d9eb8 $s26CapacitorCommunityContacts0C0C03getC0ySayAA14ContactPayloadCGAA03GetC15ProjectionInputCFySo9CNContactC_Spy10ObjectiveC8ObjCBoolVGtXEfU_ + 140\n6   CapacitorCommunityContacts          0x00000001027d9f48 $sSo9CNContactCSpy10ObjectiveC8ObjCBoolVGIggy_AbFIeggy_TR + 20\n7   CapacitorCommunityContacts          0x00000001027d9fc8 $sSo9CNContactCSpy10ObjectiveC8ObjCBoolVGIeggy_AbFIyByy_TR + 64\n8   Contacts                            0x00000001886cd2cc __74-[CNContactStore pool_enumerateContactsWithFetchRequest:error:usingBlock:]_block_invoke_2 + 120\n9   Contacts                            0x00000001886cd1e0 __74-[CNContactStore pool_enumerateContactsWithFetchRequest:error:usingBlock:]_block_invoke + 212\n10  Contacts                            0x00000001886f8878 __91-[CNDataMapperContactStore enumerateContactsAndMatchInfoWithFetchRequest:error:usingBlock:]_block_invoke_6 + 152\n11  CoreFoundation                      0x0000000180376d94 __NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__ + 16\n12  CoreFoundation                      0x000000018042f4a8 -[__NSArrayI enumerateObjectsWithOptions:usingBlock:] + 152\n13  Contacts                            0x00000001886f87c4 __91-[CNDataMapperContactStore enumerateContactsAndMatchInfoWithFetchRequest:error:usingBlock:]_block_invoke_5 + 140\n14  ContactsFoundation                  0x0000000188a849ac __43-[CNObservable enumerateObjectsUsingBlock:]_block_invoke + 92\n15  ContactsFoundation                  0x0000000188ab61b4 -[_CNBlockObserver observerDidReceiveResult:] + 168\n16  ContactsFoundation                  0x0000000188ab61b4 -[_CNBlockObserver observerDidReceiveResult:] + 168\n17  ContactsFoundation                  0x0000000188ab61b4 -[_CNBlockObserver observerDidReceiveResult:] + 168\n18  ContactsFoundation                  0x0000000188ab61b4 -[_CNBlockObserver observerDidReceiveResult:] + 168\n19  ContactsFoundation                  0x0000000188ab61b4 -[_CNBlockObserver observerDidReceiveResult:] + 168\n20  Contacts                            0x000000018869ea90 __52-[CNXPCDataMapper contactObservableForFetchRequest:]_block_invoke_2 + 116\n21  Contacts                            0x000000018869f02c __100-[CNXPCDataMapper fetchAndDecodeEncodedContactsForFetchRequest:error:cancelationToken:batchHandler:]_block_invoke_2 + 76\n22  Contacts                            0x000000018867f3d0 __85-[CNiOSABContactBuffersDecoder decodeContactsFromData:moreComing:replyHandler:error:]_block_invoke + 176\n23  Contacts                            0x00000001886bd944 -[CNContactBufferDecoder decodeContactsFromBuffer:replyHandler:] + 304\n24  Contacts                            0x000000018867f2b8 -[CNiOSABContactBuffersDecoder decodeContactsFromData:moreComing:replyHandler:error:] + 200\n25  Contacts                            0x000000018869ef94 __100-[CNXPCDataMapper fetchAndDecodeEncodedContactsForFetchRequest:error:cancelationToken:batchHandler:]_block_invoke + 184\n26  Contacts                            0x000000018869f4a0 __91-[CNXPCDataMapper fetchEncodedContactsForFetchRequest:error:cancelationToken:batchHandler:]_block_invoke + 256\n27  CoreFoundation                      0x0000000180414d00 __invoking___ + 144\n28  CoreFoundation                      0x0000000180411ee8 -[NSInvocation invoke] + 276\n29  Foundation                          0x0000000180cae608 __NSXPCCONNECTION_IS_CALLING_OUT_TO_REPLY_BLOCK__ + 12\n30  Foundation                          0x0000000180cae240 -[NSXPCConnection _decodeAndInvokeReplyBlockWithEvent:sequence:replyInfo:] + 484\n31  Foundation                          0x0000000180cb22b0 __88-[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:]_block_invoke_5 + 184\n32  Foundation                          0x0000000180cb1dcc -[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:] + 2164\n33  Foundation                          0x0000000180cb1390 -[NSXPCConnection _sendSelector:withProxy:arg1:arg2:] + 124\n34  Foundation                          0x0000000180cc4b20 _NSXPCDistantObjectSimpleMessageSend2 + 64\n35  Contacts                            0x000000018869f18c -[CNXPCDataMapper fetchEncodedContactsForFetchRequest:error:cancelationToken:batchHandler:] + 312\n36  Contacts                            0x000000018869ec20 -[CNXPCDataMapper fetchAndDecodeEncodedContactsForFetchRequest:error:cancelationToken:batchHandler:] + 244\n37  Contacts                            0x000000018869e97c __52-[CNXPCDataMapper contactObservableForFetchRequest:]_block_invoke + 188\n38  ContactsFoundation                  0x0000000188a84088 __26-[CNObservable doOnError:]_block_invoke + 232\n39  ContactsFoundation                  0x0000000188a83e50 __31-[CNObservable doOnCompletion:]_block_invoke + 232\n40  ContactsFoundation                  0x0000000188a83e50 __31-[CNObservable doOnCompletion:]_block_invoke + 232\n41  ContactsFoundation                  0x0000000188a84088 __26-[CNObservable doOnError:]_block_invoke + 232\n42  ContactsFoundation                  0x0000000188a83bac __27-[CNObservable doOnCancel:]_block_invoke + 192\n43  ContactsFoundation                  0x0000000188a84890 -[CNObservable enumerateObjectsUsingBlock:] + 320\n44  Contacts                            0x00000001886f8544 __91-[CNDataMapperContactStore enumerateContactsAndMatchInfoWithFetchRequest:error:usingBlock:]_block_invoke.55 + 428\n45  Contacts                            0x000000018874dbd0 __38-[_CNContactsLogger fetchingContacts:]_block_invoke_2 + 36\n46  libsystem_trace.dylib               0x0000000180065ba8 os_activity_apply_f + 84\n47  Contacts                            0x000000018874db40 -[_CNContactsLogger fetchingContacts:] + 188\n48  Contacts                            0x00000001886f81d4 -[CNDataMapperContactStore enumerateContactsAndMatchInfoWithFetchRequest:error:usingBlock:] + 452\n49  Contacts                            0x00000001886ccfe8 -[CNContactStore pool_enumerateContactsWithFetchRequest:error:usingBlock:] + 240\n50  Contacts                            0x00000001886ccd98 -[CNContactStore enumerateContactsWithFetchRequest:error:usingBlock:] + 464\n51  CapacitorCommunityContacts          0x00000001027d9c84 $s26CapacitorCommunityContacts0C0C03getC0ySayAA14ContactPayloadCGAA03GetC15ProjectionInputCF + 420\n52  CapacitorCommunityContacts          0x00000001027ddf1c $s26CapacitorCommunityContacts0C6PluginC03getC0yySo13CAPPluginCallCF + 420\n53  CapacitorCommunityContacts          0x00000001027de20c $s26CapacitorCommunityContacts0C6PluginC03getC0yySo13CAPPluginCallCFTo + 52\n54  Capacitor                           0x000000010299a208 $s9Capacitor0A6BridgeC12handleJSCall4callyAA0D0V_tFyycfU_ + 796\n55  Capacitor                           0x000000010298e7c8 $sIeg_IeyB_TR + 48\n56  libdispatch.dylib                   0x0000000180133fa4 _dispatch_call_block_and_release + 24\n57  libdispatch.dylib                   0x0000000180135768 _dispatch_client_callout + 16\n58  libdispatch.dylib                   0x000000018013d7f8 _dispatch_lane_serial_drain + 780\n59  libdispatch.dylib                   0x000000018013e43c _dispatch_lane_invoke + 392\n60  libdispatch.dylib                   0x000000018014a624 _dispatch_workloop_worker_thread + 772\n61  libsystem_pthread.dylib             0x00000001b059a8fc _pthread_wqthread + 284\n62  libsystem_pthread.dylib             0x00000001b05996c0 start_wqthread + 8"],
"extMods" : {"caller":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"system":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"targeted":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"warnings":0},
  "lastExceptionBacktrace" : [{"imageOffset":1185724,"symbol":"__exceptionPreprocess","symbolLocation":160,"imageIndex":1},{"imageOffset":151876,"symbol":"objc_exception_throw","symbolLocation":56,"imageIndex":13},{"imageOffset":1185496,"symbol":"-[NSException initWithCoder:]","symbolLocation":0,"imageIndex":1},{"imageOffset":692196,"symbol":"-[CNContact thumbnailImageData]","symbolLocation":144,"imageIndex":17},{"imageOffset":26496,"sourceLine":155,"sourceFile":"ContactPayload.swift","symbol":"ContactPayload.fillData(_:)","imageIndex":18,"symbolLocation":5692},{"imageOffset":40632,"sourceLine":93,"sourceFile":"Contacts.swift","symbol":"closure #1 in Contacts.getContacts(_:)","imageIndex":18,"symbolLocation":140},{"imageOffset":40776,"sourceFile":"<compiler-generated>","symbol":"thunk for @callee_guaranteed (@guaranteed CNContact, @unowned UnsafeMutablePointer<ObjCBool>) -> ()","symbolLocation":20,"imageIndex":18},{"imageOffset":40904,"sourceFile":"<compiler-generated>","symbol":"thunk for @escaping @callee_guaranteed (@guaranteed CNContact, @unowned UnsafeMutablePointer<ObjCBool>) -> ()","symbolLocation":64,"imageIndex":18},{"imageOffset":352972,"symbol":"__74-[CNContactStore pool_enumerateContactsWithFetchRequest:error:usingBlock:]_block_invoke_2","symbolLocation":120,"imageIndex":17},{"imageOffset":352736,"symbol":"__74-[CNContactStore pool_enumerateContactsWithFetchRequest:error:usingBlock:]_block_invoke","symbolLocation":212,"imageIndex":17},{"imageOffset":530552,"symbol":"__91-[CNDataMapperContactStore enumerateContactsAndMatchInfoWithFetchRequest:error:usingBlock:]_block_invoke_6","symbolLocation":152,"imageIndex":17},{"imageOffset":564628,"symbol":"__NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__","symbolLocation":16,"imageIndex":1},{"imageOffset":1320104,"symbol":"-[__NSArrayI enumerateObjectsWithOptions:usingBlock:]","symbolLocation":152,"imageIndex":1},{"imageOffset":530372,"symbol":"__91-[CNDataMapperContactStore enumerateContactsAndMatchInfoWithFetchRequest:error:usingBlock:]_block_invoke_5","symbolLocation":140,"imageIndex":17},{"imageOffset":162220,"symbol":"__43-[CNObservable enumerateObjectsUsingBlock:]_block_invoke","symbolLocation":92,"imageIndex":19},{"imageOffset":364980,"symbol":"-[_CNBlockObserver observerDidReceiveResult:]","symbolLocation":168,"imageIndex":19},{"imageOffset":364980,"symbol":"-[_CNBlockObserver observerDidReceiveResult:]","symbolLocation":168,"imageIndex":19},{"imageOffset":364980,"symbol":"-[_CNBlockObserver observerDidReceiveResult:]","symbolLocation":168,"imageIndex":19},{"imageOffset":364980,"symbol":"-[_CNBlockObserver observerDidReceiveResult:]","symbolLocation":168,"imageIndex":19},{"imageOffset":364980,"symbol":"-[_CNBlockObserver observerDidReceiveResult:]","symbolLocation":168,"imageIndex":19},{"imageOffset":162448,"symbol":"__52-[CNXPCDataMapper contactObservableForFetchRequest:]_block_invoke_2","symbolLocation":116,"imageIndex":17},{"imageOffset":163884,"symbol":"__100-[CNXPCDataMapper fetchAndDecodeEncodedContactsForFetchRequest:error:cancelationToken:batchHandler:]_block_invoke_2","symbolLocation":76,"imageIndex":17},{"imageOffset":33744,"symbol":"__85-[CNiOSABContactBuffersDecoder decodeContactsFromData:moreComing:replyHandler:error:]_block_invoke","symbolLocation":176,"imageIndex":17},{"imageOffset":289092,"symbol":"-[CNContactBufferDecoder decodeContactsFromBuffer:replyHandler:]","symbolLocation":304,"imageIndex":17},{"imageOffset":33464,"symbol":"-[CNiOSABContactBuffersDecoder decodeContactsFromData:moreComing:replyHandler:error:]","symbolLocation":200,"imageIndex":17},{"imageOffset":163732,"symbol":"__100-[CNXPCDataMapper fetchAndDecodeEncodedContactsForFetchRequest:error:cancelationToken:batchHandler:]_block_invoke","symbolLocation":184,"imageIndex":17},{"imageOffset":165024,"symbol":"__91-[CNXPCDataMapper fetchEncodedContactsForFetchRequest:error:cancelationToken:batchHandler:]_block_invoke","symbolLocation":256,"imageIndex":17},{"imageOffset":1211648,"symbol":"__invoking___","symbolLocation":144,"imageIndex":1},{"imageOffset":1199848,"symbol":"-[NSInvocation invoke]","symbolLocation":276,"imageIndex":1},{"imageOffset":5891592,"symbol":"__NSXPCCONNECTION_IS_CALLING_OUT_TO_REPLY_BLOCK__","symbolLocation":12,"imageIndex":7},{"imageOffset":5890624,"symbol":"-[NSXPCConnection _decodeAndInvokeReplyBlockWithEvent:sequence:replyInfo:]","symbolLocation":484,"imageIndex":7},{"imageOffset":5907120,"symbol":"__88-[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:]_block_invoke_5","symbolLocation":184,"imageIndex":7},{"imageOffset":5905868,"symbol":"-[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:]","symbolLocation":2164,"imageIndex":7},{"imageOffset":5903248,"symbol":"-[NSXPCConnection _sendSelector:withProxy:arg1:arg2:]","symbolLocation":124,"imageIndex":7},{"imageOffset":5983008,"symbol":"_NSXPCDistantObjectSimpleMessageSend2","symbolLocation":64,"imageIndex":7},{"imageOffset":164236,"symbol":"-[CNXPCDataMapper fetchEncodedContactsForFetchRequest:error:cancelationToken:batchHandler:]","symbolLocation":312,"imageIndex":17},{"imageOffset":162848,"symbol":"-[CNXPCDataMapper fetchAndDecodeEncodedContactsForFetchRequest:error:cancelationToken:batchHandler:]","symbolLocation":244,"imageIndex":17},{"imageOffset":162172,"symbol":"__52-[CNXPCDataMapper contactObservableForFetchRequest:]_block_invoke","symbolLocation":188,"imageIndex":17},{"imageOffset":159880,"symbol":"__26-[CNObservable doOnError:]_block_invoke","symbolLocation":232,"imageIndex":19},{"imageOffset":159312,"symbol":"__31-[CNObservable doOnCompletion:]_block_invoke","symbolLocation":232,"imageIndex":19},{"imageOffset":159312,"symbol":"__31-[CNObservable doOnCompletion:]_block_invoke","symbolLocation":232,"imageIndex":19},{"imageOffset":159880,"symbol":"__26-[CNObservable doOnError:]_block_invoke","symbolLocation":232,"imageIndex":19},{"imageOffset":158636,"symbol":"__27-[CNObservable doOnCancel:]_block_invoke","symbolLocation":192,"imageIndex":19},{"imageOffset":161936,"symbol":"-[CNObservable enumerateObjectsUsingBlock:]","symbolLocation":320,"imageIndex":19},{"imageOffset":529732,"symbol":"__91-[CNDataMapperContactStore enumerateContactsAndMatchInfoWithFetchRequest:error:usingBlock:]_block_invoke.55","symbolLocation":428,"imageIndex":17},{"imageOffset":879568,"symbol":"__38-[_CNContactsLogger fetchingContacts:]_block_invoke_2","symbolLocation":36,"imageIndex":17},{"imageOffset":19368,"symbol":"os_activity_apply_f","symbolLocation":84,"imageIndex":20},{"imageOffset":879424,"symbol":"-[_CNContactsLogger fetchingContacts:]","symbolLocation":188,"imageIndex":17},{"imageOffset":528852,"symbol":"-[CNDataMapperContactStore enumerateContactsAndMatchInfoWithFetchRequest:error:usingBlock:]","symbolLocation":452,"imageIndex":17},{"imageOffset":352232,"symbol":"-[CNContactStore pool_enumerateContactsWithFetchRequest:error:usingBlock:]","symbolLocation":240,"imageIndex":17},{"imageOffset":351640,"symbol":"-[CNContactStore enumerateContactsWithFetchRequest:error:usingBlock:]","symbolLocation":464,"imageIndex":17},{"imageOffset":40068,"sourceLine":90,"sourceFile":"Contacts.swift","symbol":"Contacts.getContacts(_:)","imageIndex":18,"symbolLocation":420},{"imageOffset":57116,"sourceLine":129,"sourceFile":"ContactsPlugin.swift","symbol":"ContactsPlugin.getContacts(_:)","imageIndex":18,"symbolLocation":420},{"imageOffset":57868,"sourceFile":"<compiler-generated>","symbol":"@objc ContactsPlugin.getContacts(_:)","symbolLocation":52,"imageIndex":18},{"imageOffset":90632,"sourceLine":506,"sourceFile":"CapacitorBridge.swift","symbol":"closure #1 in CapacitorBridge.handleJSCall(call:)","imageIndex":21,"symbolLocation":796},{"imageOffset":42952,"sourceFile":"<compiler-generated>","symbol":"thunk for @escaping @callee_guaranteed () -> ()","symbolLocation":48,"imageIndex":21},{"imageOffset":8100,"symbol":"_dispatch_call_block_and_release","symbolLocation":24,"imageIndex":14},{"imageOffset":14184,"symbol":"_dispatch_client_callout","symbolLocation":16,"imageIndex":14},{"imageOffset":47096,"symbol":"_dispatch_lane_serial_drain","symbolLocation":780,"imageIndex":14},{"imageOffset":50236,"symbol":"_dispatch_lane_invoke","symbolLocation":392,"imageIndex":14},{"imageOffset":99876,"symbol":"_dispatch_workloop_worker_thread","symbolLocation":772,"imageIndex":14},{"imageOffset":14588,"symbol":"_pthread_wqthread","symbolLocation":284,"imageIndex":8},{"imageOffset":9920,"symbol":"start_wqthread","symbolLocation":8,"imageIndex":8}],

Additional context
If I remove the image projection, all works as expected.

๐Ÿš€ Requesting permission to up the game

@Idrimi @muuvmuuv @rdlabo @dotNetkow

First of all thank you for everything you guys have done to make this plugin available for the capacitor community. ๐Ÿ’ช

I have noticed maintenance of this plugin has somewhat stalled. Maybe the interest of the maintainer has shifted, or maybe they simply lack the time. Which is totally fair of course. Any work done for the open source community is just an extra, especially when it's done without any compensation at all. ๐ŸŽ–๏ธ

I was in need of a few (yet) unimplemented features. Recently I started adding those features to this plugin in a private fork. Eventually things escalated a bit, and I ended up refactoring a lot and finally I just wrote everything from scratch again. Haha.

I like to share my work with the capacitor community. It will close all but one open issues. I have written the plugin to support Capacitor v3, but I will also apply the necessary changes to support v4. That way both versions of Capacitor can be supported with the exact same plugin API.

I could just create a new repo and npm package. But I think it's more desirable to not create a bunch of different repositories every time a new maintainers stands up and refactors a bunch of stuff. So therefore I am requesting the permission of you guys to mostly take over the maintainership of this plugin and release a v3 (unfortunately a v2 has just been shipped, so these will be following each other shortly, but oh well) and a v4 versions of the plugin.

Sidenote: I already have the necessary permissions and roles for this repository and npm, so you do not need to do anything in case you guys agree @dotNetkow ๐Ÿ˜„

Running Gradle build - failed! [capacitor] [error] - July 2022

When trying to run my app with this plugin as well as the example application (https://github.com/byrdsandbytes/capContactsDemo) i get the following errors when running 'ionic capacitor run android'.

Running Gradle build - failed!
[capacitor] [error]

  • What went wrong:
    [capacitor] A problem occurred configuring project ':capacitor-community-contacts'.
    [capacitor] > Could not resolve all artifacts for configuration ':capacitor-community-contacts:classpath'.
    [capacitor] > Could not resolve org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.61.

I ran the following commands before trying to run the application on android.

  • npm install
  • ionic run build
  • ionic cap sync

'Plugins' is deprecated.ts(6385) -- Old version of importing capacitor plugins in v2 will be removed in v4

In the documentation we are supposed to import this plugin like so:

import { Plugins } from "@capacitor/core";

const { Contacts } = Plugins;

This method of importing plugins will be removed in version 4 of capacitor and is currently deprecated in v3. Other plugins, such as the geolocation plugin (https://capacitorjs.com/docs/apis/geolocation) have made this change like so:

import { Geolocation } from '@capacitor/geolocation';

Just bringing this to people's attention as something that will need to be fixed for this plugin to work in version 4.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.