如何用HMS Nearby Service给自己的APP开发一个名片交换功能?
在工作和生活中,遇见新的同事或者合作伙伴,交换名片是一个常见的用户需求,纸质名片常忘带、易丢失,是客户的一个痛点。因此,市场上出现了很多交换电子名片的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能力不仅仅可以用来做面对面交换名片,还可以帮助开发者实现很多有趣的功能,例如:
- 竞技类手游中的面对面组队功能
- 棋牌类手游中的面对面约局功能
- 近场AA收款功能
- 音乐曲目共享功能
更详细的开发指南参考华为开发者联盟官网: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开发一个名片交换功能?的更多相关文章
- 如何用HMS Nearby Service给自己的App添加近距离数据传输功能
当你给朋友发送手机资料时,过了很久进度条却动也不动:当你想发送大文件给同事时,仅一个文件就用光了你所有流量:当你跟朋友乘坐飞机时想一起玩游戏时,却因没有网络无奈放弃. 们生活中似乎经常能遇到这 ...
- 如何用HMS Core位置和地图服务实现附近地点路径规划功能
日常出行中,路径规划是很重要的部分.用户想要去往某个地点,获取到该地点的所有路径,再根据预估出行时间自行选择合适的路线,极大方便出行.平时生活中也存在大量使用场景,在出行类App中,根据乘客的目的地可 ...
- Android | 教你如何用代码开发一个拍照翻译小程序
引子 想必有很多小伙伴喜欢外出旅游,能去海外玩一圈那是更好不过了,旅游前大家一定会对吃.穿.住.行.游玩路线做各种攻略,然后满怀期待的出发- 想象中的旅游 出发前,想象中的旅游目的地可能有漂亮 ...
- 如何用Nearby Service开发针对附近人群的精准广告推送功能
当你想找一家餐厅吃饭,却不知道去哪家,这时候手机跳出一条通知,为你自动推送附近优质餐厅的信息,你会点击查看吗?当你还在店内纠结于是否买下一双球鞋时,手机应用给了你发放了老顾客5折优惠券,这样的广告 ...
- Nearby Service新特性:Wi-Fi分享
PART 1: Wi-Fi分享功能介绍 朋友来家里做客.顾客到店里用餐-当他们想要给自己的手机链接Wi-Fi时,总免不了询问Wi-Fi名称和密码..这种问密码和给密码的过程十分麻烦,常常还会有听错或者 ...
- Android | 教你如何用华为HMS MLKit 图像分割 SDK开发一个证件照DIY小程序
Android | 教你如何用华为HMS MLKit 图像分割 SDK开发一个证件照DIY小程序 引子 上期给大家介绍了如何使用如何用华为HMS MLKit SDK 三十分钟在安卓上开发一个微笑抓 ...
- Android | 教你如何用华为HMS MLKit SDK 三十分钟在安卓上开发一个微笑抓拍神器
Android | 只要三十分钟就可以在手机上开发一个微笑抓拍神器!!! 前言 前段时间Richard Yu在发布会上给大家介绍了华为HMS Core4.0,回顾发布会信息请戳: 华为面向全球发布HM ...
- php怎么做网站?如何用PHP开发一个完整的网站?
1.PHPer应具备的知识 (1)PHP知识: 熟练掌握基础函数,PHP语句(条件.循环),数组(排序.读取),函数(内部 构造),运算(数学 逻辑),面向对象(继承 接口 封装 多态静态属性)等. ...
- SharePoint 2013 APP 开发示例 (六)服务端跨域访问 Web Service (REST API)
上个示例(SharePoint 2013 APP 开发示例 (五)跨域访问 Web Service (REST API))是基于JavaScript,运行在web browser内去访问REST AP ...
随机推荐
- Java实现 LeetCode 535 TinyURL 的加密与解密(位运算加密)
535. TinyURL 的加密与解密 TinyURL是一种URL简化服务, 比如:当你输入一个URL https://leetcode.com/problems/design-tinyurl 时,它 ...
- Java实现 LeetCode 232 用栈实现队列
232. 用栈实现队列 使用栈实现队列的下列操作: push(x) – 将一个元素放入队列的尾部. pop() – 从队列首部移除元素. peek() – 返回队列首部的元素. empty() – 返 ...
- Java实现 蓝桥杯VIP 算法提高 字符串跳步
问题描述 给定一个字符串,你需要从第start位开始每隔step位输出字符串对应位置上的字符. 输入格式 第一行一个只包含小写字母的字符串. 第二行两个非负整数start和step,意义见上. 输出格 ...
- Java实现 基础算法 水仙花数
public class 水仙花数 { public static void main(String[] args) { for (int i = 100; i < 1000; i++) { i ...
- java实现第七届蓝桥杯搭积木
搭积木 题目描述 小明最近喜欢搭数字积木, 一共有10块积木,每个积木上有一个数字,0~9. 搭积木规则: 每个积木放到其它两个积木的上面,并且一定比下面的两个积木数字小. 最后搭成4层的金字塔形,必 ...
- LNMP zabbix 4.4
硬件配置需求 环境 平台 CPU/内存 数据库 硬盘 监控主机数 小型 CentOS 2CPU/1GB MySQL.InnoDB 普通 100 中型 CentOS 2CPU/2GB MySQL.Inn ...
- 记录RecyclerView的位置并进行恢复
//监听RecyclerView滚动状态 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Overri ...
- 第一章03-Activity的启动模式
Activity的LaunchMode Android中提供了四中Activity的启动模式 1. standard 2. singleTop 3. singleTask 4. signleInsta ...
- Vue点击改变属性(改变文字颜色)
<template> <div class="tab-control"> <div v-for="(item , index) in tit ...
- Redis学习笔记(十九) 发布订阅(上)
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息,它的发布与订阅功能由PUBLISH.SUBSCRIBE.PSUBSCRIBE等命令组成. ...