APNS 网站 http://www.push-notification.org
APNS 是什么?
APNS (Android Push Notification Service) 是一种在 android 上轻松实现 push notification 的功能的解决方案.
只需申请一个 API Key, 经过简单的步骤即可实现 push notification 的功能.
特点:
快速集成:提供一种比C2DM更加快捷的使用方式,避免各种限制.
无需架设服务器:通过使用"云服务",减少额外服务器负担.
可以同时推送消息到网站页面,android 手机
耗电少,占用流量少.
操作步骤:
1. 下载 libaray: com_apns.jar
2.将com_apns.jar添加到工程
3.接收 push notification
4.启动 Push Notification Service
5.配置 AndroidManifest.xml
Activity类如下:
package com.easyway.apns;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.apns.APNService;
/**
*
* APNS 网站 http://www.push-notification.org
*
*
*
* @Title:
* @Description: 实现TODO
* @Copyright:Copyright (c) 2011
* @Company:易程科技股份有限公司
* @Date:2012-7-22
* @author longgangbai
* @version 1.0
*/
public class AndroidAPNSActivity extends Activity {
private Button btnapnsSend;
private Button btnapnscancel;
private Button btnapnsstart;
private EditText tvapnsmsContent;
private final static String APNS_SERVER_SERVICE_URL="http://www.push-notification.org/handlers/apns_v1.php";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnapnsSend=(Button)findViewById(R.id.btn_apns_send);
btnapnscancel=(Button)findViewById(R.id.btn_apns_cancel);
btnapnsstart=(Button)findViewById(R.id.btn_apns_service_start);
tvapnsmsContent=(EditText)findViewById(R.id.tv_apns_service_content);
initListeners();
}
private String getDevId() {
String devId="";
TelephonyManager telmgr=(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
if(telmgr!=null){
devId=telmgr.getDeviceId();
}
return devId;
}
private void initListeners() {
/**
* 启动 Push Notification Service
* 发送Intent 启动服务,将 chanel Id 以及 此设备的标识 (chanel中唯一表示此设备的字符串)
* 传递过去:
* 备注:
* Chanel Id 在申请 API 后,登录开发者页面会看到.
* devId: chanel 内设备标识,要在chanel内保持唯一.
*/
btnapnsstart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(APNService.START);
intent.putExtra("ch", getText(R.string.channelId));
String devId =getDevId();
if(devId==null){
devId=getText(R.string.devId).toString();
}
intent.putExtra("devId", devId);
startService(intent);
Toast.makeText(AndroidAPNSActivity.this, "APNS服务启动成功!", Toast.LENGTH_SHORT).show();
}
});
/**
*
通过 rest 接口发送 Notification:
http://www.push-notification.org/handlers/apns_v1.php?ch=YourChannelId&devId=xxxxx&msg =hello world&random=0123&hash=HashCode
ch:Channel Id
devId:接收设备 Id
msg:消息
random:随机数
hash:md5(ch + devId + msg + random + apiKey)
*
*/
btnapnsSend.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//获取消息
String msg=tvapnsmsContent.getText().toString();
if(msg==null || msg.length()==0){
Toast.makeText(AndroidAPNSActivity.this, "请输入APNS 服务的消息内容!", Toast.LENGTH_SHORT).show();
return ;
}
//获取随机数
Random random=new Random(100000);
int randomNum=random.nextInt();
//获取md5的hash值
String channelId = getText(R.string.channelId).toString();
String devId = getText(R.string.devId).toString();
devId = getDevId();
String apiKey = getText(R.string.apiKey).toString();
StringBuffer sb = new StringBuffer().append(channelId).append(devId).append(msg).append(randomNum).append(apiKey);
String md5input=sb.toString();
try {
String hash = CommonUtils.md5encrypt(md5input);
StringBuffer urlsb=new StringBuffer();
urlsb.append(APNS_SERVER_SERVICE_URL);
urlsb.append("?ch="+channelId);
urlsb.append("&devId="+devId);
urlsb.append("&msg="+msg);
urlsb.append("&random="+randomNum);
urlsb.append("&hash="+hash);
Log.d("APNS URL", "网络 APNS 服务地址:"+urlsb.toString());
Integer integer=CommonUtils.doGet(urlsb.toString(), null);
switch (integer) {
case -1://不能连接云服务!
Toast.makeText(AndroidAPNSActivity.this, "不能连接云服务!", Toast.LENGTH_LONG).show();
break;
case 0:
Toast.makeText(AndroidAPNSActivity.this, "APNS 发送信息成功!", Toast.LENGTH_LONG).show();
break;
case 1:
Toast.makeText(AndroidAPNSActivity.this, "APNS服务访问失败!", Toast.LENGTH_LONG).show();
break;
case 2:
Toast.makeText(AndroidAPNSActivity.this, "APNS服务没有访问权限!", Toast.LENGTH_LONG).show();
break;
case 3:
Toast.makeText(AndroidAPNSActivity.this, "APNS服务不再线!", Toast.LENGTH_LONG).show();
break;
case 12:
Toast.makeText(AndroidAPNSActivity.this, "APNS通道连接超时!", Toast.LENGTH_LONG).show();
break;
case 13:
Toast.makeText(AndroidAPNSActivity.this, "APNS 服务中hash code不匹配!", Toast.LENGTH_LONG).show();
break;
case 14:
Toast.makeText(AndroidAPNSActivity.this, "APNS服务中请求参数无效!", Toast.LENGTH_LONG).show();
break;
case 15:
Toast.makeText(AndroidAPNSActivity.this, "APNS服务中未知错误!", Toast.LENGTH_LONG).show();
break;
default:
Toast.makeText(AndroidAPNSActivity.this, "APNS客户端解析错误!", Toast.LENGTH_LONG).show();
break;
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
});
btnapnscancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
tvapnsmsContent.setText("");
}
});
}
}
APNSBroadcastReceiver的接收类:
package com.easyway.apns;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.apns.APNService;
/**
* 接收 push notification
* 使用BroadcastReceiver接收系统广播:将APNS接收的消息
* 以通知的方式提示用户。
*
* @Title:
* @Description: 实现TODO
* @Copyright:Copyright (c) 2011
* @Company:易程科技股份有限公司
* @Date:2012-7-22
* @author longgangbai
* @version 1.0
*/
public class APNSBroadcastReceiver extends BroadcastReceiver {
private final int APNS_NOTIFICATION_ID=0x345;
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(APNService.ON_NOTIFICATION)) {
String str = intent.getStringExtra("data");
JSONObject jsonObject;
try {
jsonObject = new JSONObject(str);
String msgTitle=jsonObject.getString("msgTitle");
String msgcontentText=jsonObject.getString("msgContent");
//初始化Notification对象:
PendingIntent pi=PendingIntent.getActivity(context, 0, intent, 0);
Notification notify=new Notification();
notify.icon=R.drawable.notification_icon;
notify.when=System.currentTimeMillis();
notify.defaults=Notification.DEFAULT_SOUND;
notify.defaults=Notification.DEFAULT_ALL;
notify.setLatestEventInfo(context, msgTitle, msgcontentText, pi);
//获得NotificationManager对象的引用:
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager notifyMgr = (NotificationManager) context.getSystemService(ns);
notifyMgr.notify(APNS_NOTIFICATION_ID, notify);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
工具类:
package com.easyway.apns;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import android.util.Log;
/**
*
*
* @Title:
* @Description: 实现TODO
* @Copyright:Copyright (c) 2011
* @Company:易程科技股份有限公司
* @Date:2012-7-22
* @author longgangbai
* @version 1.0
*/
public abstract class CommonUtils {
public static final String SUCCESS="1";
public static final String FAILURE="0";
private static final String key="MD5";
/**
* md加密的算法
*
* @param md5Str
* @return
* @throws NoSuchAlgorithmException
* @throws IOException
*/
public static String md5encrypt(String md5Str) throws NoSuchAlgorithmException {
MessageDigest md5 = MessageDigest.getInstance(key);
byte[] byteArray =md5Str.getBytes();
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i=0; i<md5Bytes.length; i++)
{
int val = ((int) md5Bytes[i] ) & 0xff;
if (val < 16) hexValue.append("0");
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
/**
* 处理REST请求GET的类
* @param requestUrl
* @param paramsMap
*/
public static Integer doGet(String requestUrl,Map<String,String> paramsMap){
// 定义待请求的URL
// 创建HttpClient实例
HttpClient client = new DefaultHttpClient();
// 根据URL创建HttpGet实例
HttpGet post = new HttpGet(requestUrl);
HttpParams params=new BasicHttpParams();
// 设置需要传递的参数
if(paramsMap!=null && !paramsMap.isEmpty()){
Set<Entry<String,String>> paramsMapset=paramsMap.entrySet();
for (Entry<String, String> entry : paramsMapset) {
params.setParameter(entry.getKey(), entry.getValue());
}
}
post.setParams(params);
try {
// 设置URL编码
post.setHeader("content-type", "charset=UTF-8");
// 发送请求并获取反馈
HttpResponse response = client.execute(post);
// 解析返回的内容
String result = EntityUtils.toString(response.getEntity());
Log.d("响应结果:", "APNS 服务响应的结果:"+result);
String reponseCode=parseXML(result);
return new Integer(reponseCode);
} catch (Exception e) {
e.printStackTrace();
return 16;
}
}
/**
* 解析返回的xml响应的结果
* @param dom
* @return
*/
public static String parseXML(String dom){
try {
InputStream inputStream =new ByteArrayInputStream(dom.getBytes());
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(inputStream);
// 获取根节点
Element root = document.getDocumentElement();
return root.getAttribute("result");
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "-1";
}
}
配置:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.easyway.apns" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" /> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.READ_LOGS"/> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:label="@string/app_name" android:name="AndroidAPNSActivity" > <intent-filter > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- APNS Service服务 --> <!-- APNS 广播接收机制 --> <receiver android:name="APNSBroadcastReceiver"> <intent-filter> <action android:name="com.apnsd.APNService.NOTIFICATION" /> </intent-filter> </receiver> <service android:name="com.apns.APNService"></service> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> </manifest>