在React Native应用程序中访问设备的联系人列表

在React Native应用程序中访问设备的联系人列表

在这个例子中,我们将看到如何在 React Native 中访问联系人列表。 在 React Native 中访问联系人列表非常简单 react-native-contacts 图书馆。 这个库提供了一个 Contacts 组件可以帮助您访问联系人列表、添加或更新任何联系人并可以打开联系人菜单。 以下是该库提供的 API 列表

  • getAll Promise<Contact()> – 返回 全部 作为对象数组的联系人
  • getAllWithoutPhotos – 与…一样 getAll 在 Android 上,但在 iOS 上,它不会返回联系人照片的 URI(因为创建图像的开销很大)
  • getContactById(contactId) – 具有定义的 contactId 的联系人(如果不存在则为 null)
  • getCount() – 联系人数量
  • getPhotoForId(contactId) – 联系人照片的 URI(或 null)
  • addContact (联系人) – 将联系人添加到地址簿。
  • openContactForm (contact) – 创建一个新联系人并显示在contactsUI中。
  • openExistingContact (contact) – 其中 contact 是具有有效 recordID 的对象
  • updateContact (contact) – 其中 contact 是具有有效 recordID 的对象
  • deleteContact (contact) – 其中 contact 是具有有效 recordID 的对象
  • getContactsMatchingString (string) – 其中 string 是与名称(名字、中间名、家庭)匹配的任何字符串
  • getContactsByPhoneNumber (string) – 其中 string 是要匹配的电话号码。
  • getContactsByEmailAddress (string) – 其中 string 是要匹配的电子邮件地址。
  • checkPermission () – 检查访问联系人的权限 仅限 iOS
  • requestPermission () – 请求访问通讯录的权限 仅限 iOS
  • writePhotoToPath () – 将联系人照片写入给定路径 仅限安卓

推荐:修复Windows 11 OBS Studio无法录制音频

访问联系人列表

在此示例中,我们将仅讨论 React Native 应用程序中设备联系人的列表。 这是帮助我们访问联系人列表的代码片段。

Contacts.getAll() 
    .then(contacts => {
        contacts.sort((a, b) => 
           a.givenName.toLowerCase() > b.givenName.toLowerCase()
        ); 
        setContacts(contacts); 
    })
    .catch(e => { 
        alert('Permission to access contacts was denied'); 
        console.warn('Permission to access contacts was denied'); 
    });

我使用了 getAll API,它将立即提供所有联系人列表。 getAll 是一个数据库密集型过程,可能需要很长时间才能完成,具体取决于联系人列表的大小。 因此,建议您访问 getAll 在需要之前调用方法,并缓存结果以供将来使用。

项目概况

在此示例中,我们将创建设备联系人列表,并使用搜索栏来过滤联系人,单击该联系人后,我们将在默认联系人菜单中打开该联系人。

屏幕启动后,我们将检查平台,如果是Android,我们将请求运行时权限,然后调用loadContacts函数,否则对于iOS,我们将直接调用loadContacts函数。 此 loadContacts 函数将访问设备的联系人列表,并提供与 Promise 相同的功能。 获取联系人后,我们将从 A 到 Z 对列表进行排序

contacts.sort((a, b) =>
  a.givenName.toLowerCase() > b.givenName.toLowerCase()
);

一旦我们准备好联系人列表,我们将在列表视图中呈现该列表。

我们还将有一个搜索栏,它将帮助我们从列表中搜索联系人。 用户可以通过手机号码或姓名进行搜索,为此,我们将分别使用 getContactsByPhoneNumber 和 getContactsMatchingString。 用户单击任何联系人后,我们将调用 openExistingContact API,该 API 将在默认联系人查看器中打开该联系人。 要打开任何现有的联系人,我们将使用

Contacts.openExistingContact(contact)

我希望您现在知道我们要做什么。 现在让我们从示例开始。

制作 React Native 应用程序

React Native 入门将帮助您更多地了解如何制作 React Native 项目。 我们将使用 React Native 命令行界面来制作我们的 React Native 应用程序。

如果您之前安装了全局的react-native-cli软件包,请将其删除,因为它可能会导致意外问题:

npm uninstall -g react-native-cli @react-native-community/cli

运行以下命令创建一个新的 React Native 项目

npx react-native init ProjectName

如果你想使用特定的 React Native 版本启动一个新项目,你可以使用 –version 参数:

npx react-native init ProjectName --version X.XX.X

注意如果上述命令失败,您可能使用的是旧版本 react-native 或者 react-native-cli 在您的电脑上全局安装。 尝试卸载 cli 并使用 npx 运行 cli。

这将在项目目录中创建一个带有名为 App.js 的索引文件的项目结构。

安装依赖

使用 Contacts 我们需要安装 react-native-contacts 包裹。 要安装它,请打开终端并跳入您的项目

cd ProjectName

运行以下命令

npm install react-native-contacts --save

该命令会将所有依赖项复制到您的node_module目录中,您可以在以下位置找到该目录 node_module 名为的目录 react-native-contacts

CocoaPods 安装

请使用以下命令安装CocoaPods

npx pod-install

Android 访问联系人列表的权限

我们正在访问设备的联系人列表,这是敏感信息,因此我们需要向 AndroidManifest.xml 文件。 请在 AndroidMnifest.xml 中添加以下权限。

YourProject -> android -> app -> main -> AndroidMnifest.xml

<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
允许目的
写联系人创建和更新设备的联系方式
读取联系人读取设备的联系方式

在React Native应用程序中访问设备的联系人列表
有关权限的更多信息,您可以查看这篇文章。

iOS 访问联系人列表的权限

请按照以下步骤在iOS项目中添加访问联系人列表的权限。

打开项目 YourProject -> ios -> YourProject.xcworkspace 在 Xcode 中。

1. 在 Xcode 中打开项目后,单击左侧栏中的项目,您将在工作区中看到多个选项。

2. 选择信息选项卡 info.plist

3. 单击加号按钮添加权限键“隐私-联系人使用说明”以及弹出权限对话框时可见的值。

联系人列表权限 iOS

项目结构

例如,我们需要创建以下目录结构。 创建一个 components 目录然后创建2个文件名 Avatar.jsListItem.js 在里面。

联系人列表 项目结构

如果您已经创建了目录结构,那么您可以进入下一步以替换其中的代码。

在 React Native 中访问联系人列表的代码

应用程序.js

在任何代码编辑器中打开 App.js 并将代码替换为以下代码

// Access Device’s Contact List in React Native App
// https://aboutreact.com/access-contact-list-react-native/

// Import React
import React, {useState, useEffect} from 'react';

// Import all required component
import {
  PermissionsAndroid,
  Platform,
  SafeAreaView,
  StyleSheet,
  Text,
  View,
  FlatList,
  TextInput,
} from 'react-native';

import Contacts from 'react-native-contacts';
import ListItem from './components/ListItem';

const App = () => {
  let (contacts, setContacts) = useState(());

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

  const loadContacts = () => {
    Contacts.getAll()
      .then(contacts => {
        contacts.sort(
          (a, b) => 
          a.givenName.toLowerCase() > b.givenName.toLowerCase(),
        );
        setContacts(contacts);
      })
      .catch(e => {
        alert('Permission to access contacts was denied');
        console.warn('Permission to access contacts was denied');
      });
  };

  const search = (text) => {
    const phoneNumberRegex = 
      /\b(\+)?(()?(0-9){2,6}())?(-\s\.)?(-\s\/\.0-9){3,15}\b/m;
    if (text === '' || text === null) {
      loadContacts();
    } else if (phoneNumberRegex.test(text)) {
      Contacts.getContactsByPhoneNumber(text).then(contacts => {
        contacts.sort(
          (a, b) => 
          a.givenName.toLowerCase() > b.givenName.toLowerCase(),
        );
        setContacts(contacts);
        console.log('contacts', contacts);
      });
    } else {
      Contacts.getContactsMatchingString(text).then(contacts => {
        contacts.sort(
          (a, b) => 
          a.givenName.toLowerCase() > b.givenName.toLowerCase(),
        );
        setContacts(contacts);
        console.log('contacts', contacts);
      });
    }
  };

  const openContact = (contact) => {
    console.log(JSON.stringify(contact));
    Contacts.openExistingContact(contact);
  };

  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.container}>
        <Text style={styles.header}>
          Access Contact List in React Native
        </Text>
        <TextInput
          onChangeText={search}
          placeholder="Search"
          style={styles.searchBar}
        />
        <FlatList
          data={contacts}
          renderItem={(contact) => {
            {
              console.log('contact -> ' + JSON.stringify(contact));
            }
            return (
              <ListItem
                key={contact.item.recordID}
                item={contact.item}
                onPress={openContact}
              />
            );
          }}
          keyExtractor={(item) => item.recordID}
        />
      </View>
    </SafeAreaView>
  );
};
export default App;

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  header: {
    backgroundColor: '#4591ed',
    color: 'white',
    paddingHorizontal: 15,
    paddingVertical: 15,
    fontSize: 20,
  },
  searchBar: {
    backgroundColor: '#f0eded',
    paddingHorizontal: 30,
    paddingVertical: Platform.OS === 'android' ? undefined : 15,
  },
});

ListItem.js

在任何代码编辑器中打开 Components/ListItem.js 并将代码替换为以下代码

// Access Device’s Contact List in React Native App
// https://aboutreact.com/access-contact-list-react-native/

import React, {memo} from 'react';
import {View, TouchableOpacity, Text, StyleSheet} from 'react-native';

import PropTypes from 'prop-types';
import Avatar from './Avatar';

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;
};

const ListItem = (props) => {
  const shouldComponentUpdate = () => {
    return false;
  };
  const {item, onPress} = props;
  return (
    <View>
      <TouchableOpacity onPress={() => onPress(item)}>
        <View style={styles.itemContainer}>
          <View style={styles.leftElementContainer}>
            <Avatar
              img={
                item.hasThumbnail ?
                  {uri: item.thumbnailPath} : undefined
              }
              placeholder={getAvatarInitials(
                `${item.givenName} ${item.familyName}`,
              )}
              width={40}
              height={40}
            />
          </View>
          <View style={styles.rightSectionContainer}>
            <View style={styles.mainTitleContainer}>
              <Text
                style={
                  styles.titleStyle
                }>{`${item.givenName} ${item.familyName}`}</Text>
            </View>
          </View>
        </View>
      </TouchableOpacity>
    </View>
  );
};

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,
  },
  titleStyle: {
    fontSize: 16,
  },
});

export default memo(ListItem);

ListItem.propTypes = {
  item: PropTypes.object,
  onPress: PropTypes.func,
};

Avatar.js

在任何代码编辑器中打开 Components/Avatar.js 并将代码替换为以下代码

// Access Device’s Contact List in React Native App
// https://aboutreact.com/access-contact-list-react-native/

import React from 'react';
import {Image, View, Text, StyleSheet} from 'react-native';
import PropTypes from 'prop-types';

const Avatar = (props) => {
  const renderImage = () => {
    const {img, width, height, roundedImage} = 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>
    );
  };

  const renderPlaceholder = () => {
    const {placeholder, width, height, roundedPlaceholder} = 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>
    );
  };

  const {img, width, height} = props;
  const {container} = styles;
  return (
    <View style={(container, props.style, {width, height})}>
      {img ? renderImage() : 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',
  },
});

Avatar.propTypes = {
  img: Image.propTypes.source,
  placeholder: PropTypes.string,
  width: PropTypes.number.isRequired,
  height: PropTypes.number.isRequired,
  roundedImage: PropTypes.bool,
  roundedPlaceholder: PropTypes.bool,
};

Avatar.defaultProps = {
  roundedImage: true,
  roundedPlaceholder: true,
};

export default Avatar;

运行 React Native 应用程序

再次打开终端并使用跳转到您的项目。

cd ProjectName

1. 启动 Metro Bundler

首先,您需要启动 Metro,React Native 附带的 JavaScript 捆绑器。 要启动 Metro 捆绑程序,请运行以下命令

npx react-native start

一旦您启动 Metro Bundler,它将永远在您的终端上运行,直到您将其关闭。 让 Metro Bundler 在自己的终端中运行。 打开一个新终端并运行该应用程序。

2.启动React Native应用程序

在 Android 虚拟设备或真实调试设备上运行项目

npx react-native run-android

或在 iOS 模拟器上运行(仅限 macOS)

npx react-native run-ios

输出截图

安卓

联系人列表示例 android 屏幕截图 1联系人列表示例 android 屏幕截图 2联系人列表示例 android 屏幕截图 3

IOS

这是您在 React Native 应用程序中访问设备联系人列表的方法。 如果您有任何疑问或想分享有关该主题的内容,您可以在下面发表评论或在此处联系我们。

推荐:如何在后台运行Linux命令


发表评论