一、背景

996的工作压力巨大,大家为了更好地隔离工作和生活,已经不满足于一机两号,而是直接进行两机两号的物理隔离。

工作的通讯录不想放在生活手机上,但有时确实需要在生活机上查看,这时候使用云同步不大合适,而本应用恰巧能够满足该使用场景。

用户在工作机和生活机上都安装该应用,并在工作机上通过按钮将本地通讯簿读取出来后,存入分布式数据库中,并通过分布式协同操作拉起生活机上的相同应用进行展示。

二、代码实现

本应用主要功能是由本地读取通讯簿,通过分布式数据库传递给远端设备并拉起远端应用展示,从而达到在远端看到数据的效果。

读取联系人

鸿蒙的联系人操作方式要比Android的友好多的多,完全面向对象,屏蔽了那些复杂的表结构,不用时刻想着操作后就要commit,否则不生效。也不用随时随地握这一个_id增删改查,鸿蒙的开发小哥哥们都帮我们把这些事在底层搞定了,所以在鸿蒙系统上使用的十分顺滑。

鸿蒙的联系人操作的核心在于ContactsHelper这个类,通过构造不同的联系人特性来对联系人的不同属性进行查看、插入、修改与删除,具体代码如下。

private List<Contact> readContacts() {
        ContactsHelper contactsHelper = new ContactsHelper(getContext());
        ContactAttributes contactAttributes = new ContactAttributes();
        contactAttributes.add(ContactAttributes.Attribute.ATTR_NAME);
        contactAttributes.add(ContactAttributes.Attribute.ATTR_PHONE);
        ContactsCollection contactsCollection = contactsHelper.queryContacts(null, contactAttributes);
        Contact contact = contactsCollection.next();
        List<Contact> contacts = new ArrayList<>();
        StringBuilder datas = new StringBuilder();
        String device = KvManagerFactory.getInstance()
                .createKvManager(new KvManagerConfig(getContext()))
                .getLocalDeviceInfo().getName();
        while (contact != null) {
            contacts.add(contact);
            LogUtil.info(TAG, contact.getName().getFullName());
            String name = contact.getName().getFullName();
            String num = contact.getPhoneNumbers() == null ? "" : contact.getPhoneNumbers().get(0).getPhoneNumber();
            StringBuilder sb = new StringBuilder();
            sb.append(name).append(SEPARATOR).append(num).append(SEPARATOR).append(device);
            mContactList.add(new ContactItemViewHolder(name, num, device));
            contact = contactsCollection.next();
            datas.append(sb.toString()).append(SEPARATOR_DATA);
        }
        singleKvStore.putString(CONSTACTS_KEY, datas.toString());
        return contacts;
    }
读取对端联系人
private void readRemoteContacts() {
        String remoteData = singleKvStore.getString(CONSTACTS_KEY);
        LogUtil.info(TAG, "remote data:" + remoteData);
        String[] datas = remoteData.split(SEPARATOR_DATA);
        for (String data : datas) {
            String[] params = data.split(SEPARATOR);
            mContactList.add(new ContactItemViewHolder(params[0], params[1], params[2]));
        }
    }
分布式操作

本应用主要使用SingleKvStore分布式数据库功能传递联系人信息,由本端存入,再拉起对端,由对端显示。 该部分代码主要参考Codelab的demo,套用了其中分布式的范式代码,具体实现可以见工程代码。

权限管理权限声明
"reqPermissions": [
      {
        "reason": "多设备协同",
        "name": "ohos.permission.DISTRIBUTED_DATASYNC",
        "usedScene": {
          "ability": [
            "com.xlab.xlabtestapp.slice.MainAbilitySlice"
          ],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.READ_CONTACTS",
        "reason": "需要联系人权限",
        "usedScene": {
          "ability": [
            "com.xlab.xlabtestapp.slice.MainAbilitySlice"
          ],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.WRITE_CONTACTS",
        "reason": "需要联系人权限",
        "usedScene": {
          "ability": [
            "com.xlab.xlabtestapp.slice.MainAbilitySlice"
          ],
          "when": "always"
        }
      }
    ]
动态请求

鸿蒙中高危权限需要动态请求,并且第一次新增时,还要求进行重新签名。

private void requestPermissions() {
        String[] permissions = {
                SystemPermission.READ_CONTACTS, SystemPermission.WRITE_CONTACTS, SystemPermission.DISTRIBUTED_DATASYNC
        };
        List<String> permissionsToProcess = new ArrayList<>();
        for (String permission : permissions) {
            if (verifySelfPermission(permission) != IBundleManager.PERMISSION_GRANTED
                    && canRequestPermission(permission)) {
                permissionsToProcess.add(permission);
            }
        }
        requestPermissionsFromUser(permissionsToProcess.toArray(new String[0]), 0);
    }

其中联系人是高危权限,不知道为啥远程模拟签名总是显示没有连接鸿蒙设备,但是真机上是没问题的。

四、遇到的坑

本项目开发中遇到了大量机制性的坑。

高危权限申请

联系人权限申请,一直只声明了,但是没有进行动态请求,导致权限一直不生效。具体权限管理方法见上文。

真机签名

实体机安装应用时,需要进行签名,该签名具体设置步骤请参照。 使用真机进行调试

远程模拟机调试

这是我遇到最大的坑了,至今还在坑里蹲着。 a. 首先想用DevEco进行远程模拟调试分布式应用,需要升级到3.0.0; b. 联系人权限在使用远程模拟调试时,签名一直无法成功,只能在真机上进行调测;

五、夸夸HarmonyOs

开发过安卓的联系人的小伙伴都知道,安卓的联系人操作直接操作provider,虽然功能强大,但是学习成本很高,很多同学都因此劝退。

但这波使用鸿蒙系统进行通讯录开发,使用的鸿蒙联系人接口,都是十分简单易懂联系人对象,十分友好。感谢这个模块开发工作者的辛勤劳动。

当然要是能给一份中文文档,联系人这个模块就更加易于上手了。

六、工程代码

https://gitee.com/kiba03/HarmonyOSDevelopLab