• 如何用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能力不仅仅可以用来做面对面交换名片,还可以帮助开发者实现很多有趣的功能,例如:

    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
    原作者:赵照

  • 相关阅读:
    不使用动态sql语句,正确书写case when中的null处理
    VC项目配置详解(转)
    JAXWS 访问SSL 的WebService 老是HTTP transport error: Connection refused错误的解决办法。
    [转]为什么开发人员工作10多年了还会迷茫?没有安全感?
    Tomcat 6.0.24 不兼容的APR版本问题
    WPF滚动条嵌套,响应鼠标滑轮事件的处理
    SqlServer无备份下误删数据恢复
    今天发现竟然有一个粉丝!!!
    好用的开源轻量级DHCP和DNS服务软件“Dual DHCP DNS Server”
    Windows下源码获取
  • 原文地址:https://www.cnblogs.com/developer-huawei/p/13161580.html
Copyright © 2020-2023  润新知