Android APP必备高级功能,消息推送之MQTT - CSDN博客

标签: | 发表时间:2018-09-20 09:45 | 作者:
出处:https://blog.csdn.net

本文已授权微信公众号《鸿洋》原创首发,转载请务必注明出处。

1. Android端实现消息推送的几种方式

  1. 轮询:客户端定时向服务器请求数据。伪推送。缺点:费电,费流量。
  2. 拦截短信消息。服务器需要向客户端发通知时,发送一条短信,客户端收到特定短信之后,先获取信息,然后拦截短信。伪推送。缺点:贵而且短信可能被安全软件拦截。
  3. 持久连接(Push)方式:客户端和服务器之间建立长久连接。真正的推送。
    1. Google的C2DM(Cloudto Device Messaging)。需要科学上网,国内大多数用户无法使用。
    2. XMPP。XMPP(可扩展通讯和表示协议)是基于可扩展标记语言(XML)的协议。androidpn是一个基于XMPP协议的java开源Android push notification实现。它包含了完整的客户端和服务器端。
    3. MQTT。MQTT是一个轻量级的消息发布/订阅协议,它是实现基于手机客户端的消息推送服务器的理想解决方案。

2. MQTT简介

MQTT官网: http://mqtt.org/

MQTT介绍: http://www.ibm.com

MQTT Android github: https://github.com/eclipse/paho.mqtt.android

MQTT API: http://www.eclipse.org/paho/files/javadoc/index.html

MQTT Android API: http://www.eclipse.org/paho/files/android-javadoc/index.html

建议时间充裕的同学有顺序的阅读上文五个链接内容,不充裕的同学请看下面简单的介绍(内容大多来自上面五条链接)。

MQTT 协议
客户机较小并且 MQTT 协议 高效地使用网络带宽,在这个意义上,其为轻量级。MQTT 协议支持可靠的传送和即发即弃的传输。 在此协议中,消息传送与应用程序脱离。 脱离应用程序的程度取决于写入 MQTT 客户机和 MQTT 服务器的方式。脱离式传送能够将应用程序从任何服务器连接和等待消息中解脱出来。 交互模式与电子邮件相似,但在应用程序编程方面进行了优化。

协议具有许多不同的功能:

  • 它是一种发布/预订协议。
  • 除提供一对多消息分发外,发布/预订也脱离了应用程序。对于具有多个客户机的应用程序来说,这些功能非常有用。
  • 它与消息内容没有任何关系。
  • 它通过 TCP/IP 运行,TCP/IP 可以提供基本网络连接。
  • 它针对消息传送提供三种服务质量:
    • “至多一次”
      消息根据底层因特网协议网络尽最大努力进行传递。 可能会丢失消息。
      例如,将此服务质量与通信环境传感器数据一起使用。 对于是否丢失个别读取或是否稍后立即发布新的读取并不重要。
    • “至少一次”
      保证消息抵达,但可能会出现重复。
    • “刚好一次”
      确保只收到一次消息。
      例如,将此服务质量与记帐系统一起使用。 重复或丢失消息可能会导致不便或收取错误费用。
  • 它是一种管理网络中消息流的经济方式。 例如,固定长度的标题仅 2 个字节长度,并且协议交换可最大程度地减少网络流量。
  • 它具有一种“遗嘱”功能,该功能通知订户客户机从 MQTT 服务器异常断开连接。请参阅“ 最后的消息”发布。

3. MQTT服务器搭建

  1. 点击 这里,下载Apollo服务器,解压后安装。
  2. 命令行进入安装目录bin目录下(例:E:>cd E:\MQTT\apache-apollo-1.7.1\bin)。
  3. 输入apollo create XXX(xxx为创建的服务器实例名称,例:apollo create mybroker),之后会在bin目录下创建名称为XXX的文件夹。XXX文件夹下etc\apollo.xml文件下是配置服务器信息的文件。etc\users.properties文件包含连接MQTT服务器时用到的用户名和密码,默认为admin=password,即账号为admin,密码为password,可自行更改。
  4. 进入XXX/bin目录,输入apollo-broker.cmd run开启服务器,看到如下界面代表搭建完成

success

之后在浏览器输入 http://127.0.0.1:61680/,查看是否安装成功。

4. MQTT Android客户端具体实现

基本概念:

  • topic:中文意思是“话题”。在MQTT中订阅了( subscribe)同一话题( topic)的客户端会同时收到消息推送。直接实现了“群聊”功能。
  • clientId:客户身份唯一标识。
  • qos:服务质量。
  • retained:要保留最后的断开连接信息。
  • MqttAndroidClient#subscribe():订阅某个话题。
  • MqttAndroidClient#publish(): 向某个话题发送消息,之后服务器会推送给所有订阅了此话题的客户。
  • userName:连接到MQTT服务器的用户名。
  • passWord :连接到MQTT服务器的密码。

添加依赖

      repositories {
    maven {
        url"https://repo.eclipse.org/content/repositories/paho-releases/"}
}

dependencies {
    compile'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'compile'org.eclipse.paho:org.eclipse.paho.android.service:1.1.0'}

添加限权

      <uses-permissionandroid:name="android.permission.INTERNET"/><uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE"/><uses-permissionandroid:name="android.permission.WAKE_LOCK"/>

注册Service

      <!-- Mqtt Service --><serviceandroid:name="org.eclipse.paho.android.service.MqttService"/><serviceandroid:name="com.dongyk.service.MQTTService"/>

Android端具体实现

      packagecom.dongyk.service;importandroid.app.Service;
.../**
 * MQTT长连接服务
 *
 *@author一口仨馍 联系方式 : yikousamo@gmail.com
 *@version创建时间:2016/9/16 22:06
 */publicclassMQTTServiceextendsService{publicstaticfinalString TAG = MQTTService.class.getSimpleName();privatestaticMqttAndroidClient client;privateMqttConnectOptions conOpt;//    private String host = "tcp://10.0.2.2:61613";privateString host ="tcp://192.168.1.103:61613";privateString userName ="admin";privateString passWord ="password";privatestaticString myTopic ="topic";privateString clientId ="test";@OverridepublicintonStartCommand(Intent intent,intflags,intstartId) {
        init();returnsuper.onStartCommand(intent, flags, startId);
    }publicstaticvoidpublish(String msg){
        String topic = myTopic;
        Integer qos =0;
        Boolean retained =false;try{
            client.publish(topic, msg.getBytes(), qos.intValue(), retained.booleanValue());
        }catch(MqttException e) {
            e.printStackTrace();
        }
    }privatevoidinit() {// 服务器地址(协议+地址+端口号)String uri = host;
        client =newMqttAndroidClient(this, uri, clientId);// 设置MQTT监听并且接受消息client.setCallback(mqttCallback);

        conOpt =newMqttConnectOptions();// 清除缓存conOpt.setCleanSession(true);// 设置超时时间,单位:秒conOpt.setConnectionTimeout(10);// 心跳包发送间隔,单位:秒conOpt.setKeepAliveInterval(20);// 用户名conOpt.setUserName(userName);// 密码conOpt.setPassword(passWord.toCharArray());// last will messagebooleandoConnect =true;
        String message ="{\"terminal_uid\":\""+ clientId +"\"}";
        String topic = myTopic;
        Integer qos =0;
        Boolean retained =false;if((!message.equals("")) || (!topic.equals(""))) {// 最后的遗嘱try{
                conOpt.setWill(topic, message.getBytes(), qos.intValue(), retained.booleanValue());
            }catch(Exception e) {
                Log.i(TAG,"Exception Occured", e);
                doConnect =false;
                iMqttActionListener.onFailure(null, e);
            }
        }if(doConnect) {
            doClientConnection();
        }

    }@OverridepublicvoidonDestroy() {try{
            client.disconnect();
        }catch(MqttException e) {
            e.printStackTrace();
        }super.onDestroy();
    }/** 连接MQTT服务器 */privatevoiddoClientConnection() {if(!client.isConnected() && isConnectIsNomarl()) {try{
                client.connect(conOpt,null, iMqttActionListener);
            }catch(MqttException e) {
                e.printStackTrace();
            }
        }

    }// MQTT是否连接成功privateIMqttActionListener iMqttActionListener =newIMqttActionListener() {@OverridepublicvoidonSuccess(IMqttToken arg0) {
            Log.i(TAG,"连接成功 ");try{// 订阅myTopic话题client.subscribe(myTopic,1);
            }catch(MqttException e) {
                e.printStackTrace();
            }
        }@OverridepublicvoidonFailure(IMqttToken arg0, Throwable arg1) {
            arg1.printStackTrace();// 连接失败,重连}
    };// MQTT监听并且接受消息privateMqttCallback mqttCallback =newMqttCallback() {@OverridepublicvoidmessageArrived(String topic, MqttMessage message)throwsException {

            String str1 =newString(message.getPayload());
            MQTTMessage msg =newMQTTMessage();
            msg.setMessage(str1);
            EventBus.getDefault().post(msg);
            String str2 = topic +";qos:"+ message.getQos() +";retained:"+ message.isRetained();
            Log.i(TAG,"messageArrived:"+ str1);
            Log.i(TAG, str2);
        }@OverridepublicvoiddeliveryComplete(IMqttDeliveryToken arg0) {

        }@OverridepublicvoidconnectionLost(Throwable arg0) {// 失去连接,重连}
    };/** 判断网络是否连接 */privatebooleanisConnectIsNomarl() {
        ConnectivityManager connectivityManager = (ConnectivityManager)this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connectivityManager.getActiveNetworkInfo();if(info !=null&& info.isAvailable()) {
            String name = info.getTypeName();
            Log.i(TAG,"MQTT当前网络名称:"+ name);returntrue;
        }else{
            Log.i(TAG,"MQTT 没有可用网络");returnfalse;
        }
    }@Nullable@OverridepublicIBinderonBind(Intent intent) {returnnull;
    }
}

首先初始化各个参数,之后连接服务器。连接成功之后在 http://127.0.0.1:61680/看到自动创建了名称为”topic”的 topic。这里我使用了一个真机和一个模拟器运行程序。 http://127.0.0.1:61680/服务端看到的是这个样子

serverPic

这里需要注意两个地方
1. 模拟器运行的时候 host = "tcp://10.0.2.2:61613",因为10.0.2.2 是模拟器设置的特定ip,是你电脑的别名。真机运行的时候 host = "tcp://192.168.1.103:61613"。192.168.1.103是我主机的IPv4地址,查看本机IP的cmd命令为 ipconfig/all
2. 两次运行时的 clientId不能一样(为了保证客户标识的唯一性)。

这里为了测试,在 MQTTService中暴露了一个公共方法 publish(String msg)MainActivity调用。代码如下

      publicclassMainActivityextendsActivity{@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EventBus.getDefault().register(this);
        startService(newIntent(this, MQTTService.class));
        findViewById(R.id.publishBtn).setOnClickListener(newView.OnClickListener() {@OverridepublicvoidonClick(View view) {
                MQTTService.publish("CSDN 一口仨馍");
            }
        });
    }@Subscribe(threadMode = ThreadMode.MAIN)publicvoidgetMqttMessage(MQTTMessage mqttMessage){
        Log.i(MQTTService.TAG,"get message:"+mqttMessage.getMessage());
        Toast.makeText(this,mqttMessage.getMessage(),Toast.LENGTH_SHORT).show();
    }@OverrideprotectedvoidonDestroy() {
        EventBus.getDefault().unregister(this);super.onDestroy();
    }

}

这里使用了 EventBus3.0发送消息,感兴趣的可以看下 EventBus3.0使用及源码解析。当然,你也可以使用接口回调的方式甚至直接在Service中弹出 Toast。whatever,现在点击一个客户端 MainActivity中的 Button,两个客户端已经能同时弹出消息。已经 get到数据了。接下来,show time~

相关 [android app 功能] 推荐:

Flickr 推出 Android App,頭條新功能是「即時照片共同欣賞」

- Preston U - Engadget 中文版
Flickr 新發表的第一個 Android app,基本上從拍照到後製到上傳到分享,所有的功能都包辦了. 在拍照的部份,它可以控制手機的閃光燈、快門、對焦、長寬比等,拍完後可以從十種濾鏡中選擇使用. 之後你可以將照片上傳到 Facebook、Twitter 或(廢話)Flickr,但真正有趣的功能是在分享的部份 -- 這個名為 Photo Session 的功能,讓你抓一把在線上的好友,然後可以即時地播放你的照片給他們看.

Flickr 推出 Android App,头条新功能是「实时照片共同欣赏」

- Digitalboy(张扬) - Engadget 中国版
Flickr 新发表的第一个 Android app,基本上从拍照到后制到上传到分享,所有的功能都包办了. 在拍照的部份,它可以控制手机的闪光灯、快门、对焦、长宽比等,拍完后可以从十种滤镜中选择使用. 之后你可以将照片上传到 Facebook、Twitter 或(废话)Flickr,但真正有趣的功能是在分享的部份 -- 这个名为 Photo Session 的功能,让你抓一把在在线的好友,然后可以实时地播放你的照片给他们看.

Google+ 手機App中文介面新登場, Android版完整功能教學

- 小趴 八足趴 八足 ramener - 電腦玩物
智慧型手機的用途很多(被智慧型手機殺死(取代)的十件事物,從我的Android手機經驗談起),而「使用社群」一直都是智慧型手機的重點功能,不管是噗浪、臉書、Twitter到最新的Google+,都有相應的手機App可以讓用戶快速和社群好友互動. 我自己在Android手機上,會透過「噗樂卡」連結噗浪,利用「Facebook官方App」操作臉書,使用「Twicca」玩Twitter,而目前我最喜歡的一款社群App設計則是Google原生的「Google+ App」.

Android APP必备高级功能,消息推送之MQTT - CSDN博客

- -
本文已授权微信公众号《鸿洋》原创首发,转载请务必注明出处. Android端实现消息推送的几种方式. 轮询:客户端定时向服务器请求数据. 服务器需要向客户端发通知时,发送一条短信,客户端收到特定短信之后,先获取信息,然后拦截短信. 缺点:贵而且短信可能被安全软件拦截. 持久连接(Push)方式:客户端和服务器之间建立长久连接.

Google将关闭Android App Inventor

- tinda - Solidot
新上任的Google CEO Larry Page已发誓要调整公司的重心,将精力集中中优先项目上,一些对用户有用但却对公司没有帮助的项目纷纷关闭,如Google字典服务,如Google Labs中的众多项目. 其中一个被关闭的项目是Android App Inventor. Android App Inventor由MIT计算机科学Hal Abelson领导开发,借鉴了入门级编程项目Scratch,让没有编程经验和知识的人开发Android应用程序,因此颇受教育界人士的欢迎.

Android dlib人脸识别 dlib-android-app: Android app to demo dlib-android(https://github.com/tzutalin/dlib-android). Use the prebuilt shared-lib built from dlib-android

- -

欢呼吧!App Inventor for Android 使用总结

- Hinc - TechCrunch中文站
昨日我们报道了Google App Inventor for Android,它是一个基于网页的开发环境,即使是没有开发背景的人也能通过他轻松创建Android应用程序. 这个产品已经测试了一年之久了,主要是和教育机构合作进行的测试,因此,在课堂上接触到它的学生们很可能成为Android应用暴增的主要力量.

如何在iOS与Android间移植APP

- plidezus - 雪鸮的啁啾
除了像”I am rich”这种定点打击苹果烧包族的APP外,大多数应用都会尽量覆盖包含尽可能多的用户. 这就需要考虑在iOS和Android两种主流操作系统间移植的问题. 如果为各个平台量身定做界面,就能让用户利用以往的使用习惯快速学习. 但为多个平台设计各异的界面毕竟是需要工作量的. 如何才能在跨平台移植的时候只做那些最有必要的工作呢.

Felix 的 60 个 Android App 推荐

- Wan - Felix&#39;s Blog
本猫入爪机(T-Mobile G2)半月, 折腾ROM/Kernel/App无数=.=. 现在我安装了下面这些常用到的App(Google自带的就不提啦), 供分享, 供参考.. 流量监控 最靠谱的一个… 有时候比ISP统计的还多一点点, 总之不会少. 有按月/周/天的统计报表, 有一个还不错的Widget, 而且, 能显示每个App使用了多少流量.