在工作和生活中,遇见新的同事或者合作伙伴,交换名片是一个常见的用户需求,纸质名片常忘带、易丢失,是客户的一个痛点。因此,市场上出现了很多交换电子名片的APP和小程序。那么,如何给自己的APP开发一个名片交换功能呢?

  我们可以接入华为近距离通信服务,通过近距离设备间消息订阅(Nearby Message),快速实现一对一或一对多名片交换。下图是功能演示:

  如果你对实现方式感兴趣,可以去Github去下载源代码,大家可以基于具体的应用场景优化。

  Github demo下载地址:https://github.com/HMS-Core/hms-nearby-demo/tree/master/NearbyCardExchange

开发具体步骤如下:

1. 开发准备

  如果您已经是华为的开发者,可以省略此步骤。如果您以前没有集成华为移动服务的经验,那么需要先配置AppGallery Connect,开通近距离通信服务并集成HMS SDK。相关步骤请参考官方文档

2. 添加权限

  在使用Nearby Message之前,需要添加网络权限、蓝牙权限、位置权限。在工程的AndroidManifest.xml文件中添加如下权限:

<uses-permission android:name="android.permission.INTERNET " />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- The location permission is also required in Android 6.0 or later. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

3. 代码开发

3.1 动态权限申请

  检查蓝牙开关、位置开关是否打开、网络是否可用,并对位置权限进行动态权限申请

@Override
public void onStart() {
super.onStart();
getActivity().getApplication().registerActivityLifecycleCallbacks(this);
checkPermission();
} @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
for (int i = 0; i < permissions.length; ++i) {
if (grantResults[i] != 0) {
showWarnDialog(Constants.LOCATION_ERROR);
}
}
} private void checkPermission() {
if (!BluetoothCheckUtil.isBlueEnabled()) {
showWarnDialog(Constants.BLUETOOTH_ERROR);
return;
} if (!LocationCheckUtil.isLocationEnabled(this.getActivity())) {
showWarnDialog(Constants.LOCATION_SWITCH_ERROR);
return;
} if (!NetCheckUtil.isNetworkAvailable(this.getActivity())) {
showWarnDialog(Constants.NETWORK_ERROR);
return;
} String[] deniedPermission = PermissionUtil.getDeniedPermissions(this.getActivity(), new String[] {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
});
if (deniedPermission.length > 0) {
PermissionUtil.requestPermissions(this.getActivity(), deniedPermission, 10);
}
}

3.2 封装名片发布接口和名片订阅接口

  订阅到的名片消息(onFound),把名片添加到查找名片对话框中显示;名片消息丢失时(onLost),从查找名片对话框中删除该名片

private MessageHandler mMessageHandler = new MessageHandler() {
@Override
public void onFound(Message message) {
CardInfo cardInfo = JsonUtils.json2Object(new String(message.getContent(), Charset.forName("UTF-8")),
CardInfo.class);
if (cardInfo == null) {
return;
} mSearchCardDialogFragment.addCardInfo(cardInfo);
} @Override
public void onLost(Message message) {
CardInfo cardInfo = JsonUtils.json2Object(new String(message.getContent(), Charset.forName("UTF-8")),
CardInfo.class);
if (cardInfo == null) {
return;
} mSearchCardDialogFragment.removeCardInfo(cardInfo);
}
}; private void publish(String namespace, String type, int ttlSeconds, OnCompleteListener<Void> listener) {
Message message = new Message(JsonUtils.object2Json(mCardInfo).getBytes(Charset.forName("UTF-8")), type,
namespace);
Policy policy = new Policy.Builder().setTtlSeconds(ttlSeconds).build();
PutOption option = new PutOption.Builder().setPolicy(policy).build();
Nearby.getMessageEngine(getActivity()).put(message, option).addOnCompleteListener(listener);
} private void subscribe(String namespace, String type, int ttlSeconds, OnCompleteListener<Void> listener,
GetCallback callback) {
Policy policy = new Policy.Builder().setTtlSeconds(ttlSeconds).build();
MessagePicker picker = new MessagePicker.Builder().includeNamespaceType(namespace, type).build();
GetOption.Builder builder = new GetOption.Builder().setPolicy(policy).setPicker(picker);
if (callback != null) {
builder.setCallback(callback);
}
Nearby.getMessageEngine(getActivity()).get(mMessageHandler, builder.build()).addOnCompleteListener(listener);
}

3.3 名片交换菜单处理

  面对面交换名片交换码,发布个人名片成功后,订阅名片消息

private boolean onExchangeItemSelected() {
PinCodeDialogFragment dialogFragment = new PinCodeDialogFragment(passwrod -> {
MyCardFragment.this.publish(passwrod, passwrod, Policy.POLICY_TTL_SECONDS_MAX, result -> {
if (!result.isSuccessful()) {
String str = "Exchange card fail, because publish my card fail. exception: "
+ result.getException().getMessage();
Log.e(TAG, str);
Toast.makeText(getActivity(), str, Toast.LENGTH_LONG).show();
return;
}
MyCardFragment.this.subscribe(passwrod, passwrod, Policy.POLICY_TTL_SECONDS_INFINITE, ret -> {
if (!ret.isSuccessful()) {
MyCardFragment.this.unpublish(passwrod, passwrod, task -> {
String str = "Exchange card fail, because subscribe is fail, exception("
+ ret.getException().getMessage() + ")";
if (!task.isSuccessful()) {
str = str + " and unpublish fail, exception(" + task.getException().getMessage()
+ ")";
} Log.e(TAG, str);
Toast.makeText(getActivity(), str, Toast.LENGTH_LONG).show();
});
return;
}
mSearchCardDialogFragment.setOnCloseListener(() -> {
MyCardFragment.this.unpublish(passwrod, passwrod, task -> {
if (!task.isSuccessful()) {
Toast.makeText(getActivity(), "Unpublish my card fail, exception: "
+ task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
});
MyCardFragment.this.unsubscribe(task -> {
if (!task.isSuccessful()) {
Toast.makeText(getActivity(), "Unsubscribe fail, exception: "
+ task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
});
});
mSearchCardDialogFragment.show(getParentFragmentManager(), "Search Card");
}, null);
});
});
dialogFragment.show(getParentFragmentManager(), "pin code"); return true;
}

3.4 收藏名片处理

  收藏名片时把名片加入收藏列表,名片取消收藏时把名片从参数列表中删除,并把数据保存到本地存储中。

@Override
public void onFavorite(CardInfo cardInfo, boolean isFavorite) {
if (isFavorite) {
mFavoriteMap.put(cardInfo.getId(), cardInfo);
} else {
mFavoriteMap.remove(cardInfo.getId());
}
Set<String> set = new HashSet<>(mFavoriteMap.size());
for (CardInfo card : mFavoriteMap.values()) {
set.add(JsonUtils.object2Json(card));
}
SharedPreferences sharedPreferences = getContext().getSharedPreferences("data", Context.MODE_PRIVATE);
sharedPreferences.edit().putStringSet(Constants.MY_FAVORITES_KEY, set).apply();
}

4.结后语

  本次给大家演示的demo用到了华为HMS Nearby service的近距离设备间消息订阅功能。基于Nearby Message能力不仅仅可以用来做面对面交换名片,还可以帮助开发者实现很多有趣的功能,例如:

  1. 竞技类手游中的面对面组队功能
  2. 棋牌类手游中的面对面约局功能
  3. 近场AA收款功能
  4. 音乐曲目共享功能

更详细的开发指南参考华为开发者联盟官网:https://developer.huawei.com/consumer/cn/doc/development/HMS-Guides/nearby-service-introduction


往期链接:教你如何开发一个完败Miracast的投屏新功能

原文链接:https://developer.huawei.com/consumer/cn/forum/topicview?tid=0201276303118820181&fid=18

原作者:赵照

如何用HMS Nearby Service给自己的APP开发一个名片交换功能?的更多相关文章

  1. 如何用HMS Nearby Service给自己的App添加近距离数据传输功能

      当你给朋友发送手机资料时,过了很久进度条却动也不动:当你想发送大文件给同事时,仅一个文件就用光了你所有流量:当你跟朋友乘坐飞机时想一起玩游戏时,却因没有网络无奈放弃.   们生活中似乎经常能遇到这 ...

  2. 如何用HMS Core位置和地图服务实现附近地点路径规划功能

    日常出行中,路径规划是很重要的部分.用户想要去往某个地点,获取到该地点的所有路径,再根据预估出行时间自行选择合适的路线,极大方便出行.平时生活中也存在大量使用场景,在出行类App中,根据乘客的目的地可 ...

  3. Android | 教你如何用代码开发一个拍照翻译小程序

    引子   想必有很多小伙伴喜欢外出旅游,能去海外玩一圈那是更好不过了,旅游前大家一定会对吃.穿.住.行.游玩路线做各种攻略,然后满怀期待的出发- 想象中的旅游   出发前,想象中的旅游目的地可能有漂亮 ...

  4. 如何用Nearby Service开发针对附近人群的精准广告推送功能

      当你想找一家餐厅吃饭,却不知道去哪家,这时候手机跳出一条通知,为你自动推送附近优质餐厅的信息,你会点击查看吗?当你还在店内纠结于是否买下一双球鞋时,手机应用给了你发放了老顾客5折优惠券,这样的广告 ...

  5. Nearby Service新特性:Wi-Fi分享

    PART 1: Wi-Fi分享功能介绍 朋友来家里做客.顾客到店里用餐-当他们想要给自己的手机链接Wi-Fi时,总免不了询问Wi-Fi名称和密码..这种问密码和给密码的过程十分麻烦,常常还会有听错或者 ...

  6. Android | 教你如何用华为HMS MLKit 图像分割 SDK开发一个证件照DIY小程序

    Android | 教你如何用华为HMS MLKit 图像分割 SDK开发一个证件照DIY小程序 引子   上期给大家介绍了如何使用如何用华为HMS MLKit SDK 三十分钟在安卓上开发一个微笑抓 ...

  7. Android | 教你如何用华为HMS MLKit SDK 三十分钟在安卓上开发一个微笑抓拍神器

    Android | 只要三十分钟就可以在手机上开发一个微笑抓拍神器!!! 前言 前段时间Richard Yu在发布会上给大家介绍了华为HMS Core4.0,回顾发布会信息请戳: 华为面向全球发布HM ...

  8. php怎么做网站?如何用PHP开发一个完整的网站?

    1.PHPer应具备的知识 (1)PHP知识: 熟练掌握基础函数,PHP语句(条件.循环),数组(排序.读取),函数(内部 构造),运算(数学 逻辑),面向对象(继承 接口 封装 多态静态属性)等. ...

  9. SharePoint 2013 APP 开发示例 (六)服务端跨域访问 Web Service (REST API)

    上个示例(SharePoint 2013 APP 开发示例 (五)跨域访问 Web Service (REST API))是基于JavaScript,运行在web browser内去访问REST AP ...

随机推荐

  1. Java实现蓝桥杯VIP 算法训练 矩阵乘方

    import java.util.Scanner; public class 矩阵乘方 { public static void main(String[] args) { Scanner scann ...

  2. java实现数字黑洞

    任意一个 5 位数,比如:34256,把它的各位数字打乱,重新排列,可以得到 一个最大的数:65432,一个最小的数 23456. 求这两个数字的差,得:41976,把这个数字再次重复上述过程(如果不 ...

  3. java实现逻辑推断

    A.B.C.D.E.F.G.H.I.J 共10名学生有可能参加本次计算机竞赛,也可能不参加.因为某种原因,他们是否参赛受到下列条件的约束: 如果A参加,B也参加: 如果C不参加,D也不参加: A和C中 ...

  4. Java实现 蓝桥杯 历届试题 最大子阵

    问题描述 给定一个n*m的矩阵A,求A中的一个非空子矩阵,使这个子矩阵中的元素和最大. 其中,A的子矩阵指在A中行和列均连续的一块. 输入格式 输入的第一行包含两个整数n, m,分别表示矩阵A的行数和 ...

  5. java实现第四届蓝桥杯阶乘位数

    阶乘位数 题目描述 如图p1.jpg所示,3 x 3 的格子中填写了一些整数. 我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是60. 本题的要求就是请你编程判定:对给定的m x n 的格 ...

  6. Spring 源码学习 - 单例bean的实例化过程

    本文作者:geek,一个聪明好学的同事 1. 简介 开发中我们常用@Commpont,@Service,@Resource等注解或者配置xml去声明一个类,使其成为spring容器中的bean,以下我 ...

  7. Linux RTC设备驱动

    1. 在Linux2.6.29内核中,RTC是以平台设备的方式注册进内核的. ① RTC驱动定义于文件:drivers/rtc/rtc-s3c.c static struct platform_dri ...

  8. grafana repeat 特性

    1.设置变量 成功后会自动复制变量值个数的的画图板 类似下图 设置后是不能与预览结果的,需要保存后 切换到其他dashboard 再切换回来就可以看见了 官方文档repeat说明

  9. Divisors (求解组合数因子个数)【唯一分解定理】

    Divisors 题目链接(点击) Your task in this problem is to determine the number of divisors of Cnk. Just for ...

  10. XAI/MLI 可解释机器学习系列1- 开源&paper汇总

    一直在关注可解释机器学习领域,因为确实在工作中有许多应用 模型检查,特征重要性是否符合预期和AUC一样重要 模型解释,比起虚无缥缈的模型指标,解释模型学到的规律更能说服业务方 样本解释,为什么这些用户 ...