在工作和生存中,遇见新的共事或者合作伙伴,替换名片是一个常见的用户需要,纸质名片常忘带、易失落,是客户的一个痛点。因而,市场上呈现了很多替换电子名片的APP和小程序。那么,如何给本人的APP开发一个名片替换性能呢?

咱们能够接入华为近距离通信服务,通过近距离设施间音讯订阅(Nearby Message),疾速实现一对一或一对多名片替换。下图是性能演示:

开发具体步骤如下:

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(); }

本次给大家演示的demo用到了华为HMS Nearby service的近距离设施间音讯订阅性能。基于Nearby Message能力不仅仅能够用来做面对面替换名片,还能够帮忙开发者实现很多乏味的性能,例如:

  • 竞技类手游中的面对面组队性能
  • 棋牌类手游中的面对面约局性能
  • 近场AA收款性能
  • 音乐曲目共享性能

欲了解更多详情

拜访华为近距离通信服务官网
获取华为近距离通信服务开发领导文档
华为近距离通信服务开源仓库地址:GitHub、Gitee
华为HMS Core官方论坛 
解决集成问题请到Stack Overflow

关注咱们,第一工夫理解HMS Core最新技术~