基于Java的 iOS 多线程推送通报

基于Java的 iOS 多线程推送通知

一,iOS 推荐原理

iOS 上的远程通知推荐机制,在官方的开发文档 《 Local and Push Notification Programming Guide》上已经有很清楚的描述。

下面再复习下这份指引的上的图,清晰下概念。

1. 消息流图

基于Java的 iOS 多线程推送通报


1.1  Provider 发送通知到 APNS (Apple Push Notification Server,苹果推送通知服务器)

1.2  APNS 发送通知到具体的 iOS 设备

1.3  iOS系统,通知到具体应用。

其中,Provider 是APP服务端的消息发出端,这部分是需要用户实现的事情,也是用户唯一可控的地方,其它流程完全在于苹果构建的系统的效率。


2. 总体消息流

基于Java的 iOS 多线程推送通报


从上面可以看到 APNS 的角色,是管理了 APNS 到每一个具体设备的长连接,而不是每个 Provider 到 每个 app 的长连接。这种方式的设计是基于 iOS 设备上的资源使用考虑,只要保留一个网络长连接就好,所有的 App 的通知都是通过这个长连接来推送通知。另一个方面,则是简化了整个流程的设计难度。


3. 设备到 APNS 的可信任长连接

基于Java的 iOS 多线程推送通报


4. Provider 到 APNS 的可信任连接

基于Java的 iOS 多线程推送通报


5.  Token 的注册

基于Java的 iOS 多线程推送通报

注意到:已经安装的 APP, 在 APNS 注册到 Token 之后,是要有发送到 APP Provider 即,App 自己的服务器上,见下面一点:


6. Token 流

基于Java的 iOS 多线程推送通报


二,本文前提

1. 已经在 Provider 上已经记录了所安装的 APP 已经注册的设备的 Token

2. 相关的密钥,权限方面已经配置好

3. Provider 是基于 JavaPNS 的实现, JavaPNS 项目位于: http://code.google.com/p/javapns


三,代码

package com.zhenian.app.service;


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

import javapns.Push;
import javapns.communication.exceptions.CommunicationException;
import javapns.communication.exceptions.KeystoreException;
import javapns.notification.PushedNotification;
import javapns.notification.ResponsePacket;

import org.springframework.stereotype.Service;



@Service
public class NotificationEngine  {
    // 10 个线程在后台发送通知
    public static final int EXCE_THREAD_POOL_SIZE = 10;

    private void shutdownEngine(){
        System.out.println("------------shutdownEngine-----------------------------");
        // 关闭 ExecutorService
        if(!exec.isShutdown()){
            exec.shutdown();
        }
    }
    public void init(){
        // 注册 jvm 关闭时操作
        Runtime.getRuntime().addShutdownHook(new Thread(){
            public void run() {
                .NotificationEnginethis.shutdownEngine();
            }
        });
    }
    
    public void destroy(){
        Thread t = new Thread(){
            public void run() {
                NotificationEngine.this.shutdownEngine();
            }
        };
        t.start();
    }
    
    private ExecutorService exec = Executors.newFixedThreadPool(EXCE_THREAD_POOL_SIZE);
    
    private FutureTask<List<PushedNotification>> doSendNotificationList(final String message, final int badge, final String sound, final String keystore, final String password, final boolean production, final List<String> tokens){    
        // 带返回结果发送动作
        FutureTask<List<PushedNotification>> future = new FutureTask<List<PushedNotification>>(
                new Callable<List<PushedNotification>>() {
                    public List<PushedNotification> call() {
                        List<PushedNotification> notifications = null;
                        try {
                            notifications = Push.combined(message,badge,sound,keystore,password,production,tokens);
                        } catch (CommunicationException e) {
                            e.printStackTrace();
                        } catch (KeystoreException e) {
                            e.printStackTrace();
                        }
                        return notifications;
                    }
                });
        // 提交到执行框架执行
        exec.submit(future);
        return future;
    }
    
    public void sendNotificationList(final String message, final int badge, final String sound, final String keystore, final String password, final boolean production, final List<String> tokens){    
        FutureTask<List<PushedNotification>> futrue = doSendNotificationList(message, badge,sound,keystore,password,production,tokens);
        try {
            // 阻塞至接收到返回结果。
            List<PushedNotification> list = futrue.get();
            for (PushedNotification notification : list) {
                if (notification.isSuccessful()) {
                        /* Apple accepted the notification and should deliver it */  
                        System.out.println("Push notification sent successfully to: " + notification.getDevice().getToken());
                        /* Still need to query the Feedback Service regularly */  
                } else {
                        String invalidToken = notification.getDevice().getToken();
                        /* Add code here to remove invalidToken from your database */  

                        /* Find out more about what the problem was */  
                        Exception theProblem = notification.getException();
                        //theProblem.printStackTrace();
                        log.error(theProblem.toString());

                        /* If the problem was an error-response packet returned by Apple, get it */  
                        ResponsePacket theErrorResponse = notification.getResponse();
                        if (theErrorResponse != null) {
                                log.error(theErrorResponse.getMessage());
                        }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        
    }
}


四,说明

1. 可以集成到 Java EE 应用之中

2. 也可以建立一个后台服务执行

3. JavaPNS 请参考相关文档。


THE END