极光推送Java SDK源码学习

来源:互联网 发布:金蝶kis mac版 编辑:程序博客网 时间:2024/06/04 18:44

前一段时间使用JPush搞了一下推送,服务器用的SpringMVC,所以想看看他的SDK源码。结果呢,一般般,没有很惊艳的感觉,看别人的代码总想去批评,这不好,但是有点失望吧~~

JPush核心有两个部分,一个是JPushClient,一个是Payload

JPushClient

内部有四个属性PushClient,ReportClient,DeviceClient,ScheduleClient。
这四个Client都是使用NativeHttpClient实现发送的,NativeHttpClient实现了IHttpClient接口

public interface IHttpClient {    public static final String CHARSET = "UTF-8";    public static final String CONTENT_TYPE_JSON = "application/json";    public static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded";    public static final String RATE_LIMIT_QUOTA = "X-Rate-Limit-Limit";    public static final String RATE_LIMIT_Remaining = "X-Rate-Limit-Remaining";    public static final String RATE_LIMIT_Reset = "X-Rate-Limit-Reset";    public static final String JPUSH_USER_AGENT = "JPush-API-Java-Client";    public static final int RESPONSE_OK = 200;    public enum RequestMethod {        GET,         POST,        PUT,        DELETE    }    public static final String IO_ERROR_MESSAGE = "Connection IO error. \n"            + "Can not connect to JPush Server. "            + "Please ensure your internet connection is ok. \n"            + "If the problem persists, please let us know at support@jpush.cn.";    public static final String CONNECT_TIMED_OUT_MESSAGE = "connect timed out. \n"            + "Connect to JPush Server timed out, and already retried some times. \n"            + "Please ensure your internet connection is ok. \n"            + "If the problem persists, please let us know at support@jpush.cn.";    public static final String READ_TIMED_OUT_MESSAGE = "Read timed out. \n"            + "Read response from JPush Server timed out. \n"            + "If this is a Push action, you may not want to retry. \n"            + "It may be due to slowly response from JPush server, or unstable connection. \n"            + "If the problem persists, please let us know at support@jpush.cn.";    public static Gson _gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();    //设置连接超时时间    public static final int DEFAULT_CONNECTION_TIMEOUT = (5 * 1000); // milliseconds    //设置读取超时时间    public static final int DEFAULT_READ_TIMEOUT = (30 * 1000); // milliseconds    public static final int DEFAULT_MAX_RETRY_TIMES = 3;    public ResponseWrapper sendGet(String url)             throws APIConnectionException, APIRequestException;    public ResponseWrapper sendDelete(String url)             throws APIConnectionException, APIRequestException;    public ResponseWrapper sendPost(String url, String content)             throws APIConnectionException, APIRequestException;    public ResponseWrapper sendPut(String url, String content)            throws APIConnectionException, APIRequestException;}

而NativeHttpClient的核心代码使用了HttpURLConnection,没有连接池,JPush的服务器使用了Yii做流量控制,这些我们都没办法改变

private ResponseWrapper _doRequest(String url, String content,             RequestMethod method) throws APIConnectionException, APIRequestException,             SocketTimeoutException {        LOG.debug("Send request - " + method.toString() + " "+ url);        if (null != content) {            LOG.debug("Request Content - " + content);        }        HttpURLConnection conn = null;        OutputStream out = null;        StringBuffer sb = new StringBuffer();        ResponseWrapper wrapper = new ResponseWrapper();        try {            URL aUrl = new URL(url);            if (null != _proxy) {                conn = (HttpURLConnection) aUrl.openConnection(_proxy.getNetProxy());                if (_proxy.isAuthenticationNeeded()) {                    conn.setRequestProperty("Proxy-Authorization", _proxy.getProxyAuthorization());                }            } else {                conn = (HttpURLConnection) aUrl.openConnection();            }            conn.setConnectTimeout(_connectionTimeout);            conn.setReadTimeout(_readTimeout);            conn.setUseCaches(false);            conn.setRequestMethod(method.name());            conn.setRequestProperty("User-Agent", JPUSH_USER_AGENT);            conn.setRequestProperty("Connection", "Keep-Alive");            conn.setRequestProperty("Accept-Charset", CHARSET);            conn.setRequestProperty("Charset", CHARSET);            conn.setRequestProperty("Authorization", _authCode);            conn.setRequestProperty("Content-Type", CONTENT_TYPE_JSON);            if(null == content) {                conn.setDoOutput(false);            } else {                conn.setDoOutput(true);                byte[] data = content.getBytes(CHARSET);                conn.setRequestProperty("Content-Length", String.valueOf(data.length));                out = conn.getOutputStream();                out.write(data);                out.flush();            }            int status = conn.getResponseCode();            InputStream in = null;            if (status / 100 == 2) {                in = conn.getInputStream();            } else {                in = conn.getErrorStream();            }            if (null != in) {                InputStreamReader reader = new InputStreamReader(in, CHARSET);                char[] buff = new char[1024];                int len;                while ((len = reader.read(buff)) > 0) {                    sb.append(buff, 0, len);                }            }            String responseContent = sb.toString();            wrapper.responseCode = status;            wrapper.responseContent = responseContent;            String quota = conn.getHeaderField(RATE_LIMIT_QUOTA);            String remaining = conn.getHeaderField(RATE_LIMIT_Remaining);            String reset = conn.getHeaderField(RATE_LIMIT_Reset);            wrapper.setRateLimit(quota, remaining, reset);            if (status >= 200 && status < 300) {                LOG.debug("Succeed to get response OK - responseCode:" + status);                LOG.debug("Response Content - " + responseContent);            } else if (status >= 300 && status < 400) {                LOG.warn("Normal response but unexpected - responseCode:" + status + ", responseContent:" + responseContent);            } else {                LOG.warn("Got error response - responseCode:" + status + ", responseContent:" + responseContent);                switch (status) {                case 400:                    LOG.error("Your request params is invalid. Please check them according to error message.");                    wrapper.setErrorObject();                    break;                case 401:                    LOG.error("Authentication failed! Please check authentication params according to docs.");                    wrapper.setErrorObject();                    break;                case 403:                    LOG.error("Request is forbidden! Maybe your appkey is listed in blacklist or your params is invalid.");                    wrapper.setErrorObject();                    break;                case 404:                    LOG.error("Request page is not found! Maybe your params is invalid.");                    wrapper.setErrorObject();                    break;                case 410:                    LOG.error("Request resource is no longer in service. Please according to notice on official website.");                    wrapper.setErrorObject();                case 429:                    LOG.error("Too many requests! Please review your appkey's request quota.");                    wrapper.setErrorObject();                    break;                case 500:                case 502:                case 503:                case 504:                    LOG.error("Seems encountered server error. Maybe JPush is in maintenance? Please retry later.");                    break;                default:                    LOG.error("Unexpected response.");                }                throw new APIRequestException(wrapper);            }        } catch (SocketTimeoutException e) {            if (e.getMessage().contains(KEYWORDS_CONNECT_TIMED_OUT)) {                throw e;            } else if (e.getMessage().contains(KEYWORDS_READ_TIMED_OUT)) {                throw new SocketTimeoutException(KEYWORDS_READ_TIMED_OUT);            }            LOG.debug(IO_ERROR_MESSAGE, e);            throw new APIConnectionException(IO_ERROR_MESSAGE, e);        } catch (IOException e) {            LOG.debug(IO_ERROR_MESSAGE, e);            throw new APIConnectionException(IO_ERROR_MESSAGE, e);        } finally {            if (null != out) {                try {                    out.close();                } catch (IOException e) {                    LOG.error("Failed to close stream.", e);                }            }            if (null != conn) {                conn.disconnect();            }        }        return wrapper;    }

PushPayload

    private final Platform platform;    private final Audience audience;    private final Notification notification;    private final Message message;    private Options options;    private SMS sms;

PushPayload是推送的内容,使用builder模式,分为以下几个属性:
Platform表示推送平台,ios,Android,wp
Audience表示接受者,可以有别名,标签等方式
Notification表示接受推送的一些定制,比如声音之类的(这里面还需要根据不同的平台设置,感觉和Platform有些重复)
Message表示消息具体内容
Options表示额外选项
SMS表示短信

也许是建议

  1. 没有连接池
  2. 设计了过多的model,但是却没有一个舒服的继承关系
    很多都是这样,而且重复
public interface PushModel {    public static Gson gson = new Gson();    public JsonElement toJSON();}
public interface IModel {    public JsonElement toJSON();}
  1. Result的Model为什么不能统一下一,搞了好多。。这样不行吗
public class ResultCode<T> implements Serializable {    private String errMsg;    private int errCode;    private T data;    }
  1. 命名太尴尬,”_”符号我明白是内部实现的意思,但这是java啊!private不就够了,这种C的命名看起来累人!
    private final NativeHttpClient _httpClient;    private String _baseUrl;    private String _pushPath;    private String _pushValidatePath;

如果你是JPush Java SDK的开发人员,别打我- -b
任何逃开实际开发环境的讨论代码都是耍流氓,这个我懂,但是我还是失望了

0 0
原创粉丝点击