”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 使用 JavaScript 读取电话联系人

使用 JavaScript 读取电话联系人

发布于2024-08-26
浏览:177

作者注:本文中描述的技术和流程是实验性的,仅适用于少数浏览器。在撰写本文时,联系人选取器 API 仅受 Android Chrome(从版本 80 开始)和 iOS Safari(从版本 14.5 开始,但仅在标志后面)支持。如果您想查看该功能,可以在我的网站上查看正在运行的演示。


从手机或平板电脑上的联系人列表中读取条目传统上仅限于本机应用程序。但通过联系人选择器 API,我们可以使用 JavaScript 来做到这一点。

此功能对于需要电话号码或 VoIP 等联系信息的应用程序、我们想要发现认识的人的社交网络或需要填写表单信息而不交换应用程序来查看数据的应用程序可能很有趣。

API 和设备将限制哪些属性可用。有五个标准可供开发者选择:

  • 姓名
  • 电话
  • 电子邮件
  • 地址
  • 图标

这里的复数很重要,因为一个联系人可以有多个电话、电子邮件或多个地址。为了一致性,返回的数据将始终位于数组内,即使它是单个值。稍后会详细介绍。


隐私和安全

手机上存储的联系信息可能包含我们必须谨慎对待的敏感信息。因此,我们必须考虑隐私和安全因素:

  • 联系人选取器 API 代码必须在顶级浏览上下文中运行。它可以防止外部代码(例如广告或第三方插件)读取您手机上的联系人列表。
  • 联系人选取器 API 代码只能在用户手势后运行。因此,开发人员无法完全自动化该过程。用户必须采取行动才能触发接触读取。
  • 此人必须允许访问联系人列表。这个限制是手机强加的,不是JS强加的。用户必须授予浏览器访问联系人的权限(如果还没有)。

他们第一次使用使用联系人选择器 API 的网站时,可能会收到如下消息:

Read Phone Contacts with JavaScript

有些人可能会觉得这个弹出窗口“可怕”。
 

手机每次都会显示此弹出窗口,直到用户点击“允许”。在此之前,联系人选取器 API 将不会运行。哪个好;我们希望确保用户授予适当的权限。一次性的事情也很好。每次页面运行联系人选择器 API 代码时授予授权将是一件令人头疼的事情。


API 和代码

联系人选取器 API 只定义了两个方法:

  • getProperties():返回可在设备上读取的属性列表。定义中只有五个:“地址”、“电子邮件”、“图标”(这可能不是联系人图片)、“姓名”、“电话”(电话),但设备可能不允许访问所有其中。
  • select():打开联系人弹出窗口并在用户完成操作后返回选择。它需要两个参数:要读取的属性列表和带有选项的可选对象。

这两种方法都返回 Promise,但考虑到它们触发的操作会阻塞应用程序的常规流程,我们在处理它们时应该使用 async/await。

忽略 getProperties() 并直接请求所有属性可能很诱人。但如果你这样做的话要小心:它可能会起作用,但如果任何指定的属性不可用, select() 方法将抛出异常。

例子

联系人选择器 API 的演示正在运行(在此处在线运行或观看此视频)。如果支持 API,它会显示一个按钮,用于读取联系人的电话号码、姓名和电子邮件以进行显示。

首先,我们需要按钮。正如隐私和安全部分前面详细介绍的,在调用 API 之前需要用户执行操作,因此如果没有用户交互,我们无法触发任何内容:


主要代码在 getContactData() 函数中。但在此之前,如果联系人选择器 API 不可用,那么显示该按钮有何意义呢?如果按钮不可用,我们将其隐藏。或者更好的是,让我们默认隐藏按钮(添加隐藏属性),并且仅在 API 可用时才显示它。

// only show the button if browser supports Contact Picker API
if ("contacts" in navigator) {
  document.querySelector("button").removeAttribute("hidden");
}

现在按钮逻辑已经就位,让我们关注 getContactData()。这是该函数的注释版本:

// it is asynchronous because we'll wait for the modal selection
async function getContactData() {
  // indicate what contact values will be read
  const props = ["tel", "name", "email"];

  // wrap everything in a try...catch, just in case
  try {
    // open the native contact selector (after permission is granted)
    const contacts = await navigator.contacts.select(props);

    // this will execute after the native contact selector is closed
    if (contacts.length) {
      // if there's data, show it
      alert("Selected data: "   JSON.stringify(contacts));
    } else {
      // ...if not, indicate nothing was selected
      alert("No selection done");
    }
  } catch (ex) {
    // if something fails, show the error message
    alert(ex.message)
  }
}

一旦按钮触发此功能,并且如果浏览器有权限(参见上一节的屏幕截图),则会显示联系模式,指示基本信息:读取数据的 URL、将返回什么数据以及可供选择的联系人列表。

Read Phone Contacts with JavaScript

联系人选择器显示将共享哪些信息
 

关闭模式后,contacts 变量会将数据存储在 JSON 中,作为一个数组,其中包含包含所请求信息的对象(如果联系人卡片中不可用,则可能为空)。

例如,这是选择自己作为联系人后的结果(假数据):

[
  {
    "address": [],
    "email": [ "[email protected]" ],
    "icon": [],
    "name": [ "Alvaro Montoro" ],
    "tel": [ "555-555-5555", "555-123-4567" ]
  }
]

如果数据包含图标,它将是带有图像的斑点。如果数据中包含地址,那么它将是一个更复杂的对象,包含街道、城市、国家、邮政编码等。您可以在规范中查看返回值。

但是,如果我们只选择一个联系人,为什么要使用数组呢?因为可以选择多个联系人!

选择多个联系人

可以选择多个联系人。如果我们想这样做,我们需要将第二个参数传递给 navigator.contacts.select() 方法来指示此选项。

const props = ["tel", "address", "icon", "name", "email"];
// only one option available: read multiple or only one (default)
const options = { multiple: true };

try {
  const contacts = await navigator.contacts.select(props, options);
  // ...

结果是一个联系人数组,因此本示例的其余代码可以保持不变。


上面的代码可能会令人生畏,主要是因为我添加了所有注释。这是上面代码的简单注释版本。正如您可能注意到的,这非常简单:

async function getContactData() {
  if ("contacts" in navigator) {
    const props = await navigator.contacts.getProperties();
    const options = { multiple: true };

    try {
      const contacts = await navigator.contacts.select(props, options);

      if (contacts.length) {
        // code managing the selected data
      } else {
        // code when nothing was selected
      }
    } catch (ex) {
      // code if there was an error
    }
  }
}

您可以在我的网站上查看正在运行的演示。别担心,除了将联系信息写在屏幕上之外,我不会对其进行任何操作。但如果你不相信我,请先检查一下代码。


结论:隐私优于盗版

联系信息是 PII(个人身份信息),我们必须以敏感数据所需的谨慎和安全态度对待它。

除了我不会遵循的可能的法律要求(因为我不了解它们,而且它们因国家/地区而异),以下是处理敏感数据时的一些基本准则:

  • 尊重人们的隐私。不要强迫他们分享他们不想分享的信息。
  • 以安全的方式谨慎处理数据。如果您正在处理的数据是您自己的,您会放心吗?
  • 如果不需要,请勿存储数据。阅读它,使用它,忘记它。不要存储您不使用的数据。
  • 仅获取您需要的数据。不要偷偷摸摸或阴暗。获取建立可信度和信任所需的信息。

假设 Web 应用程序在选择电话号码时尝试读取地址、姓名或电子邮件。如果这种情况发生在我身上,我会自动拒绝许可并离开网站。

因此,请探索 JavaScript 和联系人选择器 API,但请始终记住,屏幕后面有人,他们共享的数据如果落入坏人之手,可能会存在风险。别乱来。



如果您喜欢这篇关于 JavaScript 的文章,并且喜欢使用 JS 测试 Web API 和不同的东西,请查看另一篇文章:


使用 HTML 和 JavaScript 开发摇滚乐队游戏
Read Phone Contacts with JavaScript

版本声明 本文转载于:https://dev.to/alvaromontoro/read-phone-contacts-with-javascript-1j2?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • \“(1)vs.(;;):编译器优化是否消除了性能差异?\”
    \“(1)vs.(;;):编译器优化是否消除了性能差异?\”
    答案: 在大多数现代编译器中,while(1)和(1)和(;;)之间没有性能差异。编译器: perl: 1 输入 - > 2 2 NextState(Main 2 -E:1)V-> 3 9 Leaveloop VK/2-> A 3 toterloop(next-> 8 last-> 9 ...
    编程 发布于2025-07-04
  • 如何在Java字符串中有效替换多个子字符串?
    如何在Java字符串中有效替换多个子字符串?
    在java 中有效地替换多个substring,需要在需要替换一个字符串中的多个substring的情况下,很容易求助于重复应用字符串的刺激力量。 However, this can be inefficient for large strings or when working with nu...
    编程 发布于2025-07-04
  • Go语言垃圾回收如何处理切片内存?
    Go语言垃圾回收如何处理切片内存?
    Garbage Collection in Go Slices: A Detailed AnalysisIn Go, a slice is a dynamic array that references an underlying array.使用切片时,了解垃圾收集行为至关重要,以避免潜在的内存泄...
    编程 发布于2025-07-04
  • 如何在无序集合中为元组实现通用哈希功能?
    如何在无序集合中为元组实现通用哈希功能?
    在未订购的集合中的元素要纠正此问题,一种方法是手动为特定元组类型定义哈希函数,例如: template template template 。 struct std :: hash { size_t operator()(std :: tuple const&tuple)const {...
    编程 发布于2025-07-04
  • 如何为PostgreSQL中的每个唯一标识符有效地检索最后一行?
    如何为PostgreSQL中的每个唯一标识符有效地检索最后一行?
    postgresql:为每个唯一标识符在postgresql中提取最后一行,您可能需要遇到与数据集合中每个不同标识的信息相关的信息。考虑以下数据:[ 1 2014-02-01 kjkj 在数据集中的每个唯一ID中检索最后一行的信息,您可以在操作员上使用Postgres的有效效率: id dat...
    编程 发布于2025-07-04
  • MySQL中如何高效地根据两个条件INSERT或UPDATE行?
    MySQL中如何高效地根据两个条件INSERT或UPDATE行?
    在两个条件下插入或更新或更新 solution:的答案在于mysql的插入中...在重复键更新语法上。如果不存在匹配行或更新现有行,则此功能强大的功能可以通过插入新行来进行有效的数据操作。如果违反了唯一的密钥约束。实现所需的行为,该表必须具有唯一的键定义(在这种情况下为'名称'...
    编程 发布于2025-07-04
  • 在Python中如何创建动态变量?
    在Python中如何创建动态变量?
    在Python 中,动态创建变量的功能可以是一种强大的工具,尤其是在使用复杂的数据结构或算法时,Dynamic Variable Creation的动态变量创建。 Python提供了几种创造性的方法来实现这一目标。利用dictionaries 一种有效的方法是利用字典。字典允许您动态创建密钥并分...
    编程 发布于2025-07-04
  • JavaScript计算两个日期之间天数的方法
    JavaScript计算两个日期之间天数的方法
    How to Calculate the Difference Between Dates in JavascriptAs you attempt to determine the difference between two dates in Javascript, consider this s...
    编程 发布于2025-07-04
  • 在C#中如何高效重复字符串字符用于缩进?
    在C#中如何高效重复字符串字符用于缩进?
    在基于项目的深度下固定字符串时,重复一个字符串以进行凹痕,很方便有效地有一种有效的方法来返回字符串重复指定的次数的字符串。使用指定的次数。 constructor 这将返回字符串“ -----”。 字符串凹痕= new String(' - ',depth); console.Wr...
    编程 发布于2025-07-04
  • 编译器报错“usr/bin/ld: cannot find -l”解决方法
    编译器报错“usr/bin/ld: cannot find -l”解决方法
    错误:“ usr/bin/ld:找不到-l “ 此错误表明链接器在链接您的可执行文件时无法找到指定的库。为了解决此问题,我们将深入研究如何指定库路径并将链接引导到正确位置的详细信息。添加库搜索路径的一个可能的原因是,此错误是您的makefile中缺少库搜索路径。要解决它,您可以在链接器命令中添加...
    编程 发布于2025-07-04
  • 如何有效地选择熊猫数据框中的列?
    如何有效地选择熊猫数据框中的列?
    在处理数据操作任务时,在Pandas DataFrames 中选择列时,选择特定列的必要条件是必要的。在Pandas中,选择列的各种选项。选项1:使用列名 如果已知列索引,请使用ILOC函数选择它们。请注意,python索引基于零。 df1 = df.iloc [:,0:2]#使用索引0和1 c...
    编程 发布于2025-07-04
  • 对象拟合:IE和Edge中的封面失败,如何修复?
    对象拟合:IE和Edge中的封面失败,如何修复?
    To resolve this issue, we employ a clever CSS solution that solves the problem:position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%)...
    编程 发布于2025-07-04
  • Java中假唤醒真的会发生吗?
    Java中假唤醒真的会发生吗?
    在Java中的浪费唤醒:真实性或神话?在Java同步中伪装唤醒的概念已经是讨论的主题。尽管存在这种行为的潜力,但问题仍然存在:它们实际上是在实践中发生的吗? Linux的唤醒机制根据Wikipedia关于伪造唤醒的文章,linux实现了pthread_cond_wait()功能的Linux实现,利用...
    编程 发布于2025-07-04
  • 如何修复\“常规错误:2006 MySQL Server在插入数据时已经消失\”?
    如何修复\“常规错误:2006 MySQL Server在插入数据时已经消失\”?
    How to Resolve "General error: 2006 MySQL server has gone away" While Inserting RecordsIntroduction:Inserting data into a MySQL database can...
    编程 发布于2025-07-04
  • 为什么PYTZ最初显示出意外的时区偏移?
    为什么PYTZ最初显示出意外的时区偏移?
    与pytz 最初从pytz获得特定的偏移。例如,亚洲/hong_kong最初显示一个七个小时37分钟的偏移: 差异源利用本地化将时区分配给日期,使用了适当的时区名称和偏移量。但是,直接使用DateTime构造器分配时区不允许进行正确的调整。 example pytz.timezone(...
    编程 发布于2025-07-04

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3