利用Apollo实现移动端消息推送

移动终端作为一种低功耗、断续连接网络的设备,实现服务器主动向移动终端推送消息,是每一个移动APP开发中必不可少的一个功能。针对移动端消息推送常见的解决思路有三种:

轮询(Pull)方式:客户端定时向服务器发送询问消息,一旦服务器有变化则立即同步消息。
推送(Push)方式:移动终端现在服务器端注册并告知关注的消息主体,服务器获得相关的消息之后,根据主体主动推送给移动终端。
常连接方式:移动终端与服务器端保持常连接,保证消息下发的及时性。

考虑网络流量的问题,推送方式在一般情况下是向移动APP发送消息最好的实现方式。为此,移动APP开发中常用如下几种具体解决方案:

C2DM云端推送方案, C2DM是Google为Android 2.2以上系统专门开发的,简单易用。但是发送消息数量和大小有限制,另外国内网络环境也导致APP开发采用此种解决方案风险很大。
基于MQTT协议的推送方案,MQTT是由IBM主导开发和倡导的移动端消息推送协议,是一个轻量级的消息发布/订阅协议,它是实现基于移动APP的消息推送服务器的理想解决方案。
另外还有其他一些解决方案,例如:Apple Push Notification Service (APNS)、RSMB实现推送等。

本文重点讲述基于MQTT协议的移动APP消息推送。MQTT是开源协议,关于协议的具体内容可以详细参考:http://mqtt.org/。基于MQTT协议实现的服务器端软件也比较多,开发人员可以根据自己的开发环境、熟悉程度选择,具体软件介绍可以参考:https://github.com/mqtt/mqtt.github.io/wiki/servers

基于MQTT协议实现的软件,其消息推送的基本过程均如下:
这里写图片描述
基于MQTT实现消息推送,选择合适的MQTT Broker是第一步,在我们的测试实验中模拟中,采用Apollo,Apollo是一款支持Java开发开源高性能MQTT服务端实现,关于Apollo详细介绍和安装说明可以参考:http://activemq.apache.org/apollo/documentation/mqtt-manual.html
为此,我们在如下程序中实现的MQTT消息推送基本场景如下:
1、定义ApolloMessagePublish包,采用简单的JAVA实现模拟Server发送消息给Apollo Broker。
2、定义ApolloMessagerServer包,基于Android 5.1 API开发,实现手机端消息接收。
针对Android手机端的消息接受,我们又分为两部分程序,它们分别是:
MainActivity,用户手机界面显示,我们将把从Apollo获取到的消息,及时在Textview上显示。
MQTTService,Android后台运行Service,MainActivity启动之后,一直在后台运行,获取Apollo下发的消息。
MainActivity与MQTTService之间的通讯,利用Messenger功能实现。
针对ApolloMessagerServer Android端的类图设计如下:
这里写图片描述

代码展示:
ApolloMessagePublish,包含三个类:Test, SendMessageThread, ApolloMessagePublish,其总核心是ApolloMessagePublish。具体实现代码如下:

public class Test{
    public static void main(String[] args){
        /*
        ApolloMessagePublish MQTTServerDemo=ApolloMessagePublish.getInstance();
        MQTTServerDemo.sendMessage();
        System.out.println("Successful!");
        */
        SimpleDateFormat simpleDateFormat=null;  
        simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");  
        new SendMessageThread("this is a test,here for your message12345."+simpleDateFormat.format(new Date())).start();
        System.out.println("Successful!");
    }
}

public class SendMessageThread extends Thread {
    private String message;

    public SendMessageThread(String message){
        this.message=message;
        System.out.println("initing is Ok:"+message.toString());
    }

    public void run(){
        ApolloMessagePublish.getInstance().sendMessage(this.message);
        System.out.println("Message Sent Successfully:"+this.message.toString());
    }
}


public class ApolloMessagePublish {
    // 定义变量
    private String host = "tcp://localhost:61613";
    private String userName = "admin";
    private String password = "password";

    private MqttClient client;
    private MqttTopic topic;
    private String myTopic="Topics/htjs/serverToPhone";
    private MqttMessage message;

    private static ApolloMessagePublish instance = null;

    public static ApolloMessagePublish getInstance() {
        if (instance == null)
            instance = new ApolloMessagePublish();
        return instance;
    }

    private ApolloMessagePublish(){

          try {
            client=new MqttClient(host, "Server", new MemoryPersistence());

            //Create MqttConnectOption and 初始化
            MqttConnectOptions options=new MqttConnectOptions();
            options.setCleanSession(false);
            options.setUserName(userName);
            options.setPassword(password.toCharArray());
            options.setConnectionTimeout(10);
            options.setKeepAliveInterval(20);

            client.setCallback(new MqttCallbackHandler());
            client.connect(options);

        } catch (MqttException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }

    public void sendMessage(String msg){

        message=new MqttMessage();
        message.setQos(1);
        message.setRetained(true);
        message.setPayload(msg.getBytes());
        topic=client.getTopic(myTopic);

        try {
            MqttDeliveryToken token=topic.publish(message);
            token.waitForCompletion();
        } catch (MqttPersistenceException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (MqttException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

ApolloMessagerServer是Android客户端,包含两个类:MainActivity, MQTTService,其中核心是MqttService,具体代码如下:

public class MainActivity extends Activity {

    //用于日志输出的名称
    private static String TAG = "ClientActivity";

    //定义初始化变量
    private TextView tv;
    private Messenger sMessenger;
    private boolean isConn;
    private MainActivity MA;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获取Activity的视窗
        this.tv=(TextView)this.findViewById(R.id.Service_Monitor);
        //启动消息订阅Services
        this.MA=this;
        Log.i(TAG, "----->onCreate finished");

        //启动Service
        Intent intent = new Intent(MainActivity.this,MQTTService.class);
        bindService(intent,conn,Context.BIND_AUTO_CREATE);
        Log.i(TAG, "bindService invoked !");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    //获取服务端传递过来的消息,并显示在TextView上
    private Messenger cMessenger = new Messenger(new Handler() {
        // 获取Service发送过来的消息进行处理
        @Override
        public void handleMessage(Message msg) {
            Log.i(TAG, "----->Client processes message.");
            switch (msg.what) {
            case 0:
                // 此为示例,仅仅显示获取到的消息
                String str=(String)msg.obj;
                if (str != null)
                    tv.setText(tv.getText() + "\n" + str);
                break;
            }
        }
    });

    // 定义Connection,作为启动Services的参数
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            sMessenger = new Messenger(service);
            MA.isConn = true;
            MA.setTitle("Service is connected.");
            Log.i(TAG, "----->ServiceConnection isConn is true");

            // 初始化发送给Service的消息,并将cMessenger传递给Service
            Message msg = Message.obtain();
            msg.replyTo = cMessenger;
            msg.what = 0;
            try {
                sMessenger.send(msg);
                Log.i(TAG, "----->Client sent Message to Service");
            } catch (RemoteException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            sMessenger = null;
            MA.isConn = false;
            MA.setTitle("Service is disconnected.");
            Log.i(TAG, "----->ServiceConnection isConn is flase");
        }
    };
}


public class MQTTService extends Service implements MqttCallback {

    //用于日志输出的名称名称
    private static String TAG = "MQTTService";
    //客户端Messenger
    private Messenger cMessenger;
    // variables for connect to apollo MQ
    private String host = "tcp://Host IP:61613";
    private String userName = "admin";
    private String password = "password";
    private MqttClient client;
    private MqttConnectOptions connectOptions;
    //订阅和发布主题
    private String[] myTopic = { "Topics/htjs/phoneToServer", "Topics/htjs/serverToPhone" };
    private int[] myQos = { 1, 1 };
    private ScheduledExecutorService scheduler;

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return sMessenger.getBinder();
    }

    @Override
    public void onCreate() {
        Log.i(TAG, "---->onCreate");
        init();
    }

    @Override
    public void onDestroy(){
        Log.i(TAG, "------>onDestroy");
    }

    public void init() {
        Log.i(TAG,"----->init at host:"+host);
        try {
            client = new MqttClient(host, "test", new MemoryPersistence());

            //初始化连接参数
            connectOptions = new MqttConnectOptions();
            connectOptions.setUserName(userName);
            connectOptions.setPassword(password.toCharArray());
            connectOptions.setConnectionTimeout(10);
            connectOptions.setKeepAliveInterval(20);
            connectOptions.setCleanSession(false);
            //设置回调对象,显示获取到的消息信息
            client.setCallback(this);   
        } catch (MqttException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void connect(){
        Log.i(TAG,"------>connect");    
        if(client.isConnected())
        {
            Log.i(TAG, "---->connect: "+client.isConnected());
        }else{
            new Thread(new Runnable(){
                @Override
                public void run(){
                    try{
                         // 设置连接参数
                        client.connect(connectOptions);
                        // 根据订阅获取消息
                        client.subscribe(myTopic, myQos);
                        Log.i(TAG, "connect Successful");
                    } catch (MqttSecurityException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (MqttException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
            ).start(); 
        }           
    }

    //below is the override function for MqttCallback
    @Override
    public void connectionLost(Throwable throwable) {
        // TODO Auto-generated method stub
        Log.i(TAG, "------>connectionLost");
    }

    @Override 
    public void deliveryComplete(IMqttDeliveryToken token) {
        // TODO Auto-generated method stub
        Log.i(TAG,"deliveryComplete---------" + token.isComplete());
    }

    @Override
    public void messageArrived(String topicName, MqttMessage message) throws Exception {
        // TODO Auto-generated method stub
        Log.i(TAG,"-------->messageArrived:" + message.toString());
        //将消息加入消息队列
        Message msg=Message.obtain();
        msg.what=0;
        msg.obj=message.toString();
        cMessenger.send(msg);
        Log.i(TAG, "------>Server sent message to client");
    }

    // 定义Handler,重载Handler的消息处理方法
    private Handler mHandler = new Handler() {
        // 处理消息内容的具体方法定义
        @Override
        public void handleMessage(Message msg) {
            // 定义反馈给客户端的消息内容
            switch (msg.what) {
            case 0:
                cMessenger = msg.replyTo;
                Log.i(TAG, "---> 获取客户端Messenger成功");
                connect();
            }
            super.handleMessage(msg);
        }
    };

    // 初始化Messenger,用于消息发送和接收
    private Messenger sMessenger = new Messenger(mHandler);
}
  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值