Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

react-native-contacts

Package Overview
Dependencies
Maintainers
3
Versions
110
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-native-contacts - npm Package Compare versions

Comparing version
5.0.2
to
5.0.3
+96
example/components/Avatar/index.js
import React, { Component } from "react";
import { Image, View, Text, StyleSheet } from "react-native";
import PropTypes from "prop-types";
class Avatar extends Component {
static propTypes = {
img: Image.propTypes.source,
placeholder: PropTypes.string,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
roundedImage: PropTypes.bool,
roundedPlaceholder: PropTypes.bool
};
static defaultProps = {
roundedImage: true,
roundedPlaceholder: true
};
renderImage = () => {
const { img, width, height, roundedImage } = this.props;
const { imageContainer, image } = styles;
const viewStyle = [imageContainer];
if (roundedImage)
viewStyle.push({ borderRadius: Math.round(width + height) / 2 });
return (
<View style={viewStyle}>
<Image style={image} source={img} />
</View>
);
};
renderPlaceholder = () => {
const { placeholder, width, height, roundedPlaceholder } = this.props;
const { placeholderContainer, placeholderText } = styles;
const viewStyle = [placeholderContainer];
if (roundedPlaceholder)
viewStyle.push({ borderRadius: Math.round(width + height) / 2 });
return (
<View style={viewStyle}>
<View style={viewStyle}>
<Text
adjustsFontSizeToFit
numberOfLines={1}
minimumFontScale={0.01}
style={[{ fontSize: Math.round(width) / 2 }, placeholderText]}
>
{placeholder}
</Text>
</View>
</View>
);
};
render() {
const { img, width, height } = this.props;
const { container } = styles;
return (
<View style={[container, this.props.style, { width, height }]}>
{img ? this.renderImage() : this.renderPlaceholder()}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
width: "100%"
},
imageContainer: {
overflow: "hidden",
justifyContent: "center",
height: "100%"
},
image: {
flex: 1,
alignSelf: "stretch",
width: undefined,
height: undefined
},
placeholderContainer: {
alignItems: "center",
justifyContent: "center",
backgroundColor: "#dddddd",
height: "100%"
},
placeholderText: {
fontWeight: "700",
color: "#ffffff"
}
});
export default Avatar;
import React, { Component } from "react";
import {
View,
TouchableHighlight,
Text,
StyleSheet,
Platform,
Animated
} from "react-native";
import PropTypes from "prop-types";
import { RectButton } from "react-native-gesture-handler";
import Swipeable from "react-native-gesture-handler/Swipeable";
class ListItem extends Component {
static propTypes = {
leftElement: PropTypes.element,
title: PropTypes.string,
description: PropTypes.string,
rightElement: PropTypes.element,
rightText: PropTypes.string,
onPress: PropTypes.func,
onDelete: PropTypes.func,
onLongPress: PropTypes.func,
disabled: PropTypes.bool
};
renderRightAction = (iconName, color, x, progress) => {
const trans = progress.interpolate({
inputRange: [0, 1],
outputRange: [x, 0]
});
const pressHandler = () => {
const { onDelete } = this.props;
if (onDelete) onDelete();
this.close();
};
return (
<Animated.View style={{ flex: 1, transform: [{ translateX: trans }] }}>
<RectButton
style={[styles.rightAction, { backgroundColor: color }]}
onPress={pressHandler}
>
<Text style={{ color: "#fff" }}>Delete</Text>
</RectButton>
</Animated.View>
);
};
renderRightActions = progress => (
<View style={{ width: 64, flexDirection: "row" }}>
{this.renderRightAction("trash", "#ef5350", 64, progress)}
</View>
);
renderRightActions = progress => (
<View style={{ width: 64, flexDirection: "row" }}>
{this.renderRightAction("trash", "#ef5350", 64, progress)}
</View>
);
updateRef = ref => {
this.swipeableRow = ref;
};
close = () => {
this.swipeableRow.close();
};
render() {
const {
leftElement,
title,
description,
rightElement,
rightText,
onPress,
onLongPress,
disabled
} = this.props;
const Component = onPress || onLongPress ? TouchableHighlight : View;
const {
itemContainer,
leftElementContainer,
rightSectionContainer,
mainTitleContainer,
rightElementContainer,
rightTextContainer,
titleStyle,
descriptionStyle
} = styles;
return (
<Swipeable
ref={this.updateRef}
friction={1}
renderRightActions={this.renderRightActions}
>
<Component
onPress={onPress}
onLongPress={onLongPress}
disabled={disabled}
underlayColor="#f2f3f5"
>
<View style={itemContainer}>
{leftElement ? (
<View style={leftElementContainer}>{leftElement}</View>
) : (
<View />
)}
<View style={rightSectionContainer}>
<View style={mainTitleContainer}>
<Text style={titleStyle}>{title}</Text>
{description ? (
<Text style={descriptionStyle}>{description}</Text>
) : (
<View />
)}
</View>
<View style={rightTextContainer}>
{rightText ? <Text>{rightText}</Text> : <View />}
</View>
{rightElement ? (
<View style={rightElementContainer}>{rightElement}</View>
) : (
<View />
)}
</View>
</View>
</Component>
</Swipeable>
);
}
}
const styles = StyleSheet.create({
itemContainer: {
flexDirection: "row",
minHeight: 44,
height: 63
},
leftElementContainer: {
justifyContent: "center",
alignItems: "center",
flex: 2,
paddingLeft: 13
},
rightSectionContainer: {
marginLeft: 18,
flexDirection: "row",
flex: 20,
borderBottomWidth: StyleSheet.hairlineWidth,
borderColor: "#515151"
},
mainTitleContainer: {
justifyContent: "center",
flexDirection: "column",
flex: 1
},
rightElementContainer: {
justifyContent: "center",
alignItems: "center",
flex: 0.4
},
rightTextContainer: {
justifyContent: "center",
marginRight: 10
},
titleStyle: {
fontSize: 16
},
descriptionStyle: {
fontSize: 14,
color: "#515151"
},
rightAction: {
alignItems: "center",
flex: 1,
justifyContent: "center"
}
});
export default ListItem;
import React, { Component } from "react";
import PropTypes from "prop-types";
import {
View,
TextInput,
UIManager,
LayoutAnimation,
Animated,
ActivityIndicator,
TouchableOpacity,
TouchableWithoutFeedback,
Text,
StyleSheet
} from "react-native";
class SearchBar extends Component {
static propTypes = {
searchPlaceholder: PropTypes.string,
onClear: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
onChangeText: PropTypes.func
};
static defaultProps = {
searchPlaceholder: "Search",
onClear: () => null,
onFocus: () => null,
onBlur: () => null,
onChangeText: () => null
};
constructor(props) {
super(props);
this.state = {
hasFocus: false,
isEmpty: true,
showLoader: false
};
}
focus = () => {
this.input.focus();
};
blur = () => {
this.input.blur();
};
clear = () => {
this.input.clear();
this.onChangeText("");
this.props.onClear();
};
cancel = () => {
this.blur();
};
showLoader = () => {
this.setState({
showLoader: true
});
};
hideLoader = () => {
this.setState({
showLoader: false
});
};
onFocus = () => {
this.props.onFocus();
if (UIManager.configureNextLayoutAnimation) LayoutAnimation.easeInEaseOut();
this.setState({
hasFocus: true
});
};
onBlur = () => {
this.props.onBlur();
if (UIManager.configureNextLayoutAnimation) LayoutAnimation.easeInEaseOut();
this.setState({
hasFocus: false
});
};
onChangeText = text => {
this.props.onChangeText(text);
this.setState({ isEmpty: text === "" });
};
render() {
const {
container,
inputStyle,
leftIconStyle,
rightContainer,
rightIconStyle,
activityIndicator
} = styles;
const { searchPlaceholder, style } = this.props;
const { hasFocus, isEmpty, showLoader } = this.state;
const inputStyleCollection = [inputStyle];
if (hasFocus) inputStyleCollection.push({ flex: 1 });
return (
<TouchableWithoutFeedback onPress={this.focus} style={style}>
<Animated.View style={container}>
<View style={leftIconStyle}>
<Text>🔍</Text>
</View>
<TextInput
onFocus={this.onFocus}
onBlur={this.onBlur}
onChangeText={this.onChangeText}
placeholder={searchPlaceholder}
style={inputStyleCollection}
placeholderTextColor="#515151"
autoCorrect={false}
ref={ref => {
this.input = ref;
}}
/>
<View style={rightContainer}>
{hasFocus && showLoader ? (
<ActivityIndicator
key="loading"
style={activityIndicator}
color="#515151"
/>
) : (
<View />
)}
{hasFocus && !isEmpty ? (
<TouchableOpacity onPress={this.clear}>
<View style={rightIconStyle}>
<Text>ⅹ</Text>
</View>
</TouchableOpacity>
) : (
<View />
)}
</View>
</Animated.View>
</TouchableWithoutFeedback>
);
}
}
const styles = StyleSheet.create({
container: {
height: 40,
borderRadius: 5,
backgroundColor: "#ddd",
marginLeft: 10,
marginRight: 10,
marginBottom: 5,
marginTop: 5,
flexDirection: "row",
alignItems: "center",
justifyContent: "center"
},
inputStyle: {
alignSelf: "center",
marginLeft: 5,
height: 40,
fontSize: 14
},
leftIconStyle: {
height: 30,
justifyContent: "center",
alignItems: "center",
marginLeft: 8
},
rightContainer: {
flexDirection: "row"
},
rightIconStyle: {
height: 30,
justifyContent: "center",
alignItems: "center",
marginRight: 8
},
activityIndicator: {
marginRight: 5
}
});
export default SearchBar;

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

+24
-7

@@ -110,18 +110,35 @@ package com.rt2zz.reactnativecontacts;

/*
* Returns all contacts matching string
/**
* Retrieves contacts matching String.
* Uses raw URI when <code>rawUri</code> is <code>true</code>, makes assets copy otherwise.
*
* @param searchString String to match
* @param callback user provided callback to run at completion
*/
@ReactMethod
public void getContactsMatchingString(final String searchString, final Callback callback) {
getAllContactsMatchingString(searchString, callback);
AsyncTask<Void,Void,Void> myAsyncTask = new AsyncTask<Void,Void,Void>() {
@Override
protected Void doInBackground(final Void ... params) {
Context context = getReactApplicationContext();
ContentResolver cr = context.getContentResolver();
ContactsProvider contactsProvider = new ContactsProvider(cr);
WritableArray contacts = contactsProvider.getContactsMatchingString(searchString);
callback.invoke(null, contacts);
return null;
}
};
myAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
/**
* Retrieves contacts matching String.
* Retrieves contacts matching a phone number.
* Uses raw URI when <code>rawUri</code> is <code>true</code>, makes assets copy otherwise.
*
* @param searchString String to match
* @param phoneNumber phone number to match
* @param callback user provided callback to run at completion
*/
private void getAllContactsMatchingString(final String searchString, final Callback callback) {
@ReactMethod
public void getContactsByPhoneNumber(final String phoneNumber, final Callback callback) {
AsyncTask<Void,Void,Void> myAsyncTask = new AsyncTask<Void,Void,Void>() {

@@ -133,3 +150,3 @@ @Override

ContactsProvider contactsProvider = new ContactsProvider(cr);
WritableArray contacts = contactsProvider.getContactsMatchingString(searchString);
WritableArray contacts = contactsProvider.getContactsByPhoneNumber(phoneNumber);

@@ -136,0 +153,0 @@ callback.invoke(null, contacts);

@@ -117,2 +117,31 @@ package com.rt2zz.reactnativecontacts;

public WritableArray getContactsByPhoneNumber(String phoneNumber) {
Map<String, Contact> matchingContacts;
{
Cursor cursor = contentResolver.query(
ContactsContract.Data.CONTENT_URI,
FULL_PROJECTION.toArray(new String[FULL_PROJECTION.size()]),
ContactsContract.CommonDataKinds.Phone.NUMBER + " LIKE ? OR "
+ ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER + " LIKE ?",
new String[]{"%" + phoneNumber + "%", "%" + phoneNumber + "%"},
null
);
try {
matchingContacts = loadContactsFrom(cursor);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
WritableArray contacts = Arguments.createArray();
for (Contact contact : matchingContacts.values()) {
contacts.pushMap(contact.toMap());
}
return contacts;
}
public WritableMap getContactByRawId(String contactRawId) {

@@ -119,0 +148,0 @@

@@ -9,3 +9,3 @@ # Contributing

* write your feature
* submit a feature test on https://github.com/morenoh149/react-native-contacts-test to test it's integration
* add example usage to the example app https://github.com/rt2zz/react-native-contacts/tree/master/example
* submit a pull request on this repo, and describe:

@@ -12,0 +12,0 @@ * a brief description

@@ -141,2 +141,3 @@ apply plugin: "com.android.application"

dependencies {
implementation project(':react-native-gesture-handler')
implementation project(':react-native-contacts')

@@ -143,0 +144,0 @@ implementation fileTree(dir: "libs", include: ["*.jar"])

@@ -6,2 +6,3 @@ package com.example;

import com.facebook.react.ReactApplication;
import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
import com.rt2zz.reactnativecontacts.ReactNativeContacts;

@@ -28,2 +29,3 @@ import com.facebook.react.ReactNativeHost;

new MainReactPackage(),
new RNGestureHandlerPackage(),
new ReactNativeContacts()

@@ -30,0 +32,0 @@ );

@@ -19,1 +19,3 @@ # Project-wide Gradle settings.

# org.gradle.parallel=true
android.useAndroidX=true
android.enableJetifier=true
rootProject.name = 'example'
include ':react-native-gesture-handler'
project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
include ':react-native-contacts'

@@ -3,0 +5,0 @@ project(':react-native-contacts').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-contacts/android')

@@ -9,18 +9,26 @@ /**

import React, {Component} from 'react';
import {PermissionsAndroid, Platform, SafeAreaView, ScrollView, StyleSheet, Text, View} from 'react-native';
import Contacts from 'react-native-contacts';
import React, { Component } from "react";
import {
PermissionsAndroid,
Platform,
SafeAreaView,
ScrollView,
StyleSheet,
Text,
View,
Image
} from "react-native";
import Contacts from "react-native-contacts";
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
android:
'Double tap R on your keyboard to reload,\n' +
'Shake or press menu button for dev menu',
});
import ListItem from "./components/ListItem";
import Avatar from "./components/Avatar";
import SearchBar from "./components/SearchBar";
type Props = {};
export default class App extends Component<Props> {
constructor(props) {
super(props);
this.search = this.search.bind(this);
this.state = {

@@ -32,12 +40,9 @@ contacts: []

async componentWillMount() {
if (Platform.OS === 'android') {
PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
{
'title': 'Contacts',
'message': 'This app would like to view your contacts.'
}
).then(() => {
if (Platform.OS === "android") {
PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_CONTACTS, {
title: "Contacts",
message: "This app would like to view your contacts."
}).then(() => {
this.loadContacts();
})
});
} else {

@@ -50,18 +55,75 @@ this.loadContacts();

Contacts.getAll((err, contacts) => {
if (err === 'denied'){
console.warn('Permission to access contacts was denied');
if (err === "denied") {
console.warn("Permission to access contacts was denied");
} else {
this.setState({ contacts });
}
})
});
}
search(text) {
const phoneNumberRegex = /\b[\+]?[(]?[0-9]{2,6}[)]?[-\s\.]?[-\s\/\.0-9]{3,15}\b/m;
if (text === "" || text === null) {
this.loadContacts();
} else if (phoneNumberRegex.test(text)) {
Contacts.getContactsByPhoneNumber(text, (err, contacts) => {
this.setState({ contacts });
});
} else {
Contacts.getContactsMatchingString(text, (err, contacts) => {
this.setState({ contacts });
});
}
}
render() {
return (
<SafeAreaView style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native Contacts!</Text>
<ScrollView style={{flex: 1}}>
<Text style={styles.instructions}>
{JSON.stringify(this.state.contacts, null, '\t')}
</Text>
<View
style={{
paddingLeft: 100,
paddingRight: 100,
justifyContent: "center",
alignItems: "center"
}}
>
<Image
source={require("./logo.png")}
style={{
aspectRatio: 6,
resizeMode: "contain"
}}
/>
</View>
<SearchBar onChangeText={this.search} />
<ScrollView style={{ flex: 1 }}>
{this.state.contacts.map(contact => {
return (
<ListItem
leftElement={
<Avatar
img={
contact.hasThumbnail
? { uri: contact.thumbnailPath }
: undefined
}
placeholder={getAvatarInitials(
`${contact.givenName} ${contact.familyName}`
)}
width={40}
height={40}
/>
}
key={contact.recordID}
title={`${contact.givenName} ${contact.familyName}`}
description={`${contact.company}`}
onPress={() => Contacts.openExistingContact(contact, () => {})}
onDelete={() =>
Contacts.deleteContact(contact, () => {
this.loadContacts();
})
}
/>
);
})}
</ScrollView>

@@ -75,17 +137,19 @@ </SafeAreaView>

container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'left',
color: '#333333',
marginBottom: 5,
},
flex: 1
}
});
const getAvatarInitials = textString => {
if (!textString) return "";
const text = textString.trim();
const textSplit = text.split(" ");
if (textSplit.length <= 1) return text.charAt(0);
const initials =
textSplit[0].charAt(0) + textSplit[textSplit.length - 1].charAt(0);
return initials;
};

@@ -7,8 +7,11 @@ {

"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
"test": "jest",
"postinstall": "yarn react-native-jetifier"
},
"dependencies": {
"@jumpn/react-native-jetifier": "^0.1.4",
"react": "16.8.3",
"react-native": "0.59.5",
"react-native-contacts": "github:rt2zz/react-native-contacts"
"react-native-contacts": "https://github.com/rt2zz/react-native-contacts.git",
"react-native-gesture-handler": "^1.3.0"
},

@@ -15,0 +18,0 @@ "devDependencies": {

@@ -1,2 +0,2 @@

# react-native-device-info example project
# react-native-contacts example project

@@ -3,0 +3,0 @@ ## Installation

@@ -11,2 +11,3 @@ export function getAll(callback: (error: any, contacts: Contact[]) => void): void;

export function getContactsMatchingString(str: string, callback: (error: any, contacts: Contact[]) => void): void;
export function getContactsByPhoneNumber(phoneNumber: string, callback: (error: any, contacts: Contact[]) => void): void;
export function checkPermission(callback: (error: any, result: 'authorized' | 'denied' | 'undefined') => void): void;

@@ -61,2 +62,2 @@ export function requestPermission(callback: (error: any, result: 'authorized' | 'denied' | 'undefined') => void): void;

birthday: Birthday;
}
}

@@ -102,2 +102,41 @@ #import <AddressBook/AddressBook.h>

RCT_EXPORT_METHOD(getContactsByPhoneNumber:(NSString *)string callback:(RCTResponseSenderBlock) callback)
{
CNContactStore *contactStore = [[CNContactStore alloc] init];
if (!contactStore)
return;
[self getContactsFromAddressBook:contactStore byPhoneNumber:string callback:callback];
}
-(void) getContactsFromAddressBook:(CNContactStore *)store
byPhoneNumber:(NSString *)phoneNumber
callback:(RCTResponseSenderBlock)callback
{
NSMutableArray *contacts = [[NSMutableArray alloc] init];
NSError *contactError = nil;
NSArray *keys = @[
CNContactEmailAddressesKey,
CNContactPhoneNumbersKey,
CNContactFamilyNameKey,
CNContactGivenNameKey,
CNContactMiddleNameKey,
CNContactPostalAddressesKey,
CNContactOrganizationNameKey,
CNContactJobTitleKey,
CNContactImageDataAvailableKey,
CNContactThumbnailImageDataKey,
CNContactUrlAddressesKey,
CNContactBirthdayKey
];
CNPhoneNumber *cnPhoneNumber = [[CNPhoneNumber alloc] initWithStringValue:phoneNumber];
NSArray *arrayOfContacts = [store unifiedContactsMatchingPredicate:[CNContact predicateForContactsMatchingPhoneNumber:cnPhoneNumber]
keysToFetch:keys
error:&contactError];
[arrayOfContacts enumerateObjectsUsingBlock:^(CNContact * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSDictionary *contactDictionary = [self contactToDictionary:obj withThumbnails:true];
[contacts addObject:contactDictionary];
}];
callback(@[[NSNull null], contacts]);
}
-(void) getAllContacts:(RCTResponseSenderBlock) callback

@@ -525,7 +564,13 @@ withThumbnails:(BOOL) withThumbnails

UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:contactViewController];
UIViewController *rooViewController = (UIViewController*)[[[[UIApplication sharedApplication] delegate] window] rootViewController];
UIViewController *currentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (currentViewController.presentedViewController)
{
currentViewController = currentViewController.presentedViewController;
}
// Cover the contact view with an activity indicator so we can put it in edit mode without user seeing the transition
UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicatorView.frame = UIScreen.mainScreen.applicationFrame;
activityIndicatorView.frame = UIApplication.sharedApplication.keyWindow.frame;
[activityIndicatorView startAnimating];

@@ -535,4 +580,5 @@ activityIndicatorView.backgroundColor = [UIColor whiteColor];

[rooViewController presentViewController:navigation animated:YES completion:nil];
[currentViewController presentViewController:navigation animated:YES completion:nil];
// TODO should this 'fake click' method be used? For a brief instance

@@ -539,0 +585,0 @@ // Fake click edit button to enter edit mode

@@ -7,3 +7,3 @@ {

},
"version": "5.0.2",
"version": "5.0.3",
"description": "React Native Contacts (android & ios)",

@@ -10,0 +10,0 @@ "nativePackage": true,

@@ -1,2 +0,3 @@

# React Native Contacts
![react-native-contacts](https://github.com/rt2zz/react-native-contacts/raw/master/example/logo.png)
To contribute read [CONTRIBUTING.md](CONTRIBUTING.md).

@@ -73,3 +74,20 @@

#### Using CocoaPods (react-native 0.60 and above)
Starting with 0.60, the above instructions stop working on iOS. Instead, you have to do the following:
- Add the following line inside `ios/Podfile`
```
target 'app' do
...
pod 'react-native-contacts', :path => '../node_modules/react-native-contacts' <-- add me
...
end
```
- Run `pod install` in folder `ios`
### Android
For react native versions 0.60 and above you have to use Android X. Android X support was added to react-native-contacts in version 5.x+. If you are using rn 0.59 and below install rnc versions 4.x instead.
1. In `android/settings.gradle`

@@ -83,3 +101,3 @@

3. In `android/app/build.gradle`
2. In `android/app/build.gradle`

@@ -94,3 +112,3 @@ ```gradle

4. register module (in MainApplication.java)
3. register module (in MainApplication.java)

@@ -152,2 +170,3 @@ ```java

* `getContactsMatchingString` (string, callback) - where string is any string to match a name (first, middle, family) to
* `getContactsByPhoneNumber` (string, callback) - where string is a phone number to match to.
* `checkPermission` (callback) - checks permission to access Contacts _ios only_

@@ -232,4 +251,3 @@ * `requestPermission` (callback) - request permission to access Contacts _ios only_

}],
familyName: "Nietzsche",
givenName: "Friedrich",
displayName: "Friedrich Nietzsche"
}

@@ -328,2 +346,8 @@

## Example
You can find an example app/showcase [here](https://github.com/rt2zz/react-native-contacts/tree/master/example)
![react-native-contacts example](https://github.com/rt2zz/react-native-contacts/raw/master/example/react-native-contacts.gif)
<h2 align="center">Maintainers</h2>

@@ -330,0 +354,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet