背景
“附近的人”、“面对面建群”、“近距离点对点本地聊天”…这几个常见的功能都会出现在各大社交类软件中。可通常情况下,“附近的人”基本都只能发现距离自己几百米甚至几公里以外的人,如何缩小这个距离,实现与数米距离内的人打招呼呢?“面对面建群”如何精确的发现就在自己身边的人呢?如何不经过云服务即可直接通信与好友聊天呢?Nearby Service都可以帮你实现!下面将为大家详细讲解Nearby Service集成教程,助你打造一款更加便捷的社交聊天类应用。
应用场景介绍
这里为大家带来一个集成了Nearby Service的示例应用,这个应用利用Nearby Service能做到发现附近的人,以及基于这个能力可以实现如面对面建群、群聊、私密聊、迁移聊天记录等功能。
- 附近的人
可以为用户精准的发现附近数米的人,支持用户发现同处一室的朋友,如会议室、展厅、酒吧、咖啡厅等;
- 面对面建群
利用Nearby Service进行建群,只需在端侧即可完成建群动作,位置精确,只有同处一地的人能够进群。
- 随心聊
利用Nearby Service可以实现近距离范围内不加好友的群聊,新朋友只需到范围附近即可自动入群;离开对应范围自动退出。
- 私密聊
利用Nearby Service可以实现近距离本地点对点聊天。通信只在两个设备间进行,数据加密不上云,无需担心信息泄露;在高铁、地铁等信号不好的场所时也可以进行通信。
- 迁移聊天记录
不仅如此,Nearby Service还提供了强大的文件传输功能。当用户有多个设备需要迁移聊天记录时,可利用Nearby Service的通信接口,实现高速、免流量的数据迁移。
工具准备
- 2台安卓手机或更多
- 开发工具 Android Studio(3.X or later)
构建示例应用
- 在Android Studio中导入示例源代码。
- 注册成为华为开发者。
- 参考Nearby Service 开发准备在华为应用市场创建一个您的应用。注意:需要下载“agconnect-services.json”文件和参考指导生成签名证书并放置在app/目录下。
- 使用adb命令将生成的apk文件安装到测试手机。
关键代码
示例应用中使用的接口在官方文档Nearby Service Guides中有详细的介绍。
这个示例应用采用MVP的模式进行构建,如您想查看源代码,请根据代码路径: com\huawei\hms\nearby\im找到相应的类。
1. 附近的人
如下面代码所示NearbyPeoplePresenter类在初始化时需将view对象传入。当调用NearbyPeoplePresenter.findNearbyPeople()发现附近的人时,调用view的接口执行后续的动作。
INearbyPeopleView和后面步骤中的xxxView是一组接口,它们的具体实现是对应的Activity对象,代码路径是:com\huawei\hms\nearby\im\ui\adapter。
public NearbyPeoplePresenter(Context mContext, INearbyPeopleView view) {
super(mContext, view);
nearbyAgent = new NearbyAgent(mContext, new NearbyAgent.INearbyMessageView() {
@Override
public void onMessageFound(MessageBean messageBean) {
// notify view when found someone
view.onMemberChanged(false,messageBean);
}
@Override
public void onMessageLost(MessageBean messageBean) {
view.onMemberChanged(true,messageBean);
}
@Override
public void onMsgSendResult(boolean isSucceed, MessageBean item) {
view.onLoginResult(isSucceed,item);
if (!isSucceed) {
handler.postDelayed(() -> findNearbyPeople(),DURATION_RE_LOGIN);
}
}
});
handler = new Handler(Looper.getMainLooper());
}
public void findNearbyPeople() {
nearbyAgent.broadcastMessage(null,MessageBean.ACTION_TAG_ONLINE);
nearbyAgent.startScan();
}
2. 面对面建群
与“附近的人”类似,CreateGroupPresenter.java类在初始化时传入view对象,当调用joinGroup(groupId)接口时会加入该群组,结果会通过调用view的接口返回。
public CreateGroupPresenter(Context mContext, ICreateGroupView view) {
super(mContext, view);
nearbyAgent = new NearbyAgent(mContext, new NearbyAgent.INearbyMessageView() {
@Override
public void onMessageFound(MessageBean messageBean) {
view.onPeopleFound(messageBean);
}
@Override
public void onMessageLost(MessageBean messageBean) {}
@Override
public void onMsgSendResult(boolean isSucceed, MessageBean item) {
view.onJoinGroupResult(isSucceed,item);
}
});
}
public void joinGroup(String groupId) {
nearbyAgent.broadcastMessage(groupId,"join group");
nearbyAgent.startScan(groupId);
}
3. 随心聊
类GroupChatPresenter.java在初始化时需传入view对象。业务代码调用broadcastMessage(groupId, sendContent)发送消息到指定的群组,groupId为空时不限定群组;调用findMessage(groupId)发现指定群组的消息,发现后调用view接口返回消息。
public GroupChatPresenter(Context mContext, IGroupChatView view) {
super(mContext, view);
nearbyAgent = new NearbyAgent(mContext, new NearbyAgent.INearbyMessageView() {
@Override
public void onMessageFound(MessageBean messageBean) {
view.onMessageFound(messageBean);
}
@Override
public void onMessageLost(MessageBean messageBean) {
}
@Override
public void onMsgSendResult(boolean isSucceed, MessageBean item) {
view.onMsgSendResult(isSucceed,item);
}
});
}
public void broadcastMessage(String groupId, String sendContent) {
nearbyAgent.broadcastMessage(groupId,sendContent);
}
public void findMessage(String groupId) {
nearbyAgent.startScan(groupId);
}
4. 私密聊
私密聊的实现与上述接口有所不同,类NearbyConnectionPresenter.java提供了4个接口:
- findNearbyPeople():发现附近的人
- requestConnect():与对方建立连接
- sendMessage(String msgStr):发送字符串类型消息
- sendFile(Uri uri):发送文件
/**
* scanAndBroadcasting to find nearby people
*/
public void findNearbyPeople(){
mDiscoveryEngine.startScan(serviceId, new ScanEndpointCallback() {
@Override
public void onFound(String endpointId, ScanEndpointInfo discoveryEndpointInfo) {
Log.d(TAG, "onFound -- Nearby Connection Demo app: onFound endpoint: " + endpointId);
view.onFound(endpointId,discoveryEndpointInfo);
}
@Override
public void onLost(String endpointId) {
Log.d(TAG, "onLost -- Nearby Connection Demo app: Lost endpoint: " + endpointId);
view.onLost(endpointId);
}
}, scanOption);
}
/**
* request to connect with remote device
* @param endpointId the endpointId of remote device
*/
public void requestConnect(String endpointId) {
Log.d(TAG, "requestConnect -- endpoint: " + endpointId);
mDiscoveryEngine.requestConnect(myNameStr, endpointId, connectCallback);
}
/**
* Send message ,Data.Type.BYTES
*/
public MessageBean sendMessage(String msgStr) {
MessageBean item = new MessageBean();
item.setUserName(CommonUtil.userName);
item.setMsg(msgStr);
item.setType(MessageBean.TYPE_SEND_TEXT);
item.setSendTime(DateUtils.getCurrentTime(DateUtils.FORMAT));
Data data = Data.fromBytes(gson.toJson(item).getBytes(Charset.defaultCharset()));
mTransferEngine.sendData(mEndpointId, data);
return item;
}
/**
* send file ,Data.Type.FILE
* @param uri
*/
public Data sendFile(Uri uri) {
Data filePayload;
try {
ParcelFileDescriptor pfd = mContext.getContentResolver().openFileDescriptor(uri, "r");
filePayload = Data.fromFile(pfd);
} catch (FileNotFoundException e) {
Log.e(Constants.TAG, "File not found, cause: ", e);
return null;
}
String fileName = FileUtil.getFileRealNameFromUri(mContext, uri);
String filenameMessage = filePayload.getId() + ":" + fileName;
Data filenameBytesPayload = Data.fromBytes(filenameMessage.getBytes(StandardCharsets.UTF_8));
mTransferEngine.sendData(mEndpointId, filenameBytesPayload);
mTransferEngine.sendData(mEndpointId, filePayload);
return filePayload;
}
更多详情
- 华为开发者联盟官网:
https://developer.huawei.com/consumer/en/hms/huawei-nearbyservice?ha_source=hms1 - 获取开发指导文档:
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides-V5/introduction-0000001050040566-V5?ha_source=hms1 - 参与开发者讨论请到Reddit社区:https://www.reddit.com/r/HuaweiDevelopers/
- 下载demo和示例代码请到Github:https://github.com/HMS-Core
- 解决集成问题请到Stack Overflow:
https://stackoverflow.com/questions/tagged/huawei-mobile-services?tab=Newest