實(shí)際項(xiàng)目應(yīng)用中,應(yīng)該考慮使用開源項(xiàng)目java-apns:https://github.com/notnoop/java-apns
千萬不要用一個(gè)叫JAVAPNS的項(xiàng)目。這個(gè)開源項(xiàng)目的代碼非常爛,每次發(fā)送消息都重新建立socket連接。在apple的文檔中,都明確的說了會把這種行為當(dāng)作dos攻擊行為。性能差就更不用說了。
ios手機(jī)上要安裝對應(yīng)的應(yīng)用。該應(yīng)用與.p12證書文件應(yīng)該匹配。
apple官方的,關(guān)于APN服務(wù),和apn的feedback的文檔在這個(gè)地方:https://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/CommunicatingWIthAPS.html#//apple_ref/doc/uid/TP40008194-CH101-SW3
java版本發(fā)送apn推送代碼示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | package test; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.Socket; import java.security.KeyStore; import java.util.regex.Pattern; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; public class TestAPN { /** * @param args */ public static void main(String[] args) { String keyPath = "/data/tmp/proj.apns.p12" ; String ksType = "PKCS12" ; String ksPassword = "111111" ; String ksAlgorithm = "SunX509" ; String deviceToken = "1404c88dbb0adb92c0a85f4cd09be9707f251ae5bbecdb0a6a3e572aeb337d73" ; String serverHost = "gateway.push.apple.com" ; int serverPort = 2195 ; try { InputStream certInput = new FileInputStream(keyPath); KeyStore keyStore = KeyStore.getInstance(ksType); keyStore.load(certInput, ksPassword.toCharArray()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(ksAlgorithm); kmf.init(keyStore, ksPassword.toCharArray()); SSLContext sslContext = SSLContext.getInstance( "TLS" ); sslContext.init(kmf.getKeyManagers(), null , null ); SSLSocketFactory socketFactory = sslContext.getSocketFactory(); Socket socket = socketFactory.createSocket(serverHost, serverPort); StringBuilder content = new StringBuilder(); String text = "this is a test." ; content.append( "{\"aps\":" ); content.append( "{\"alert\":\"" ).append(text) .append( "\",\"badge\":1,\"sound\":\"" ) .append( "ping1" ).append( "\"}" ); content.append( ",\"cpn\":{\"t0\":" ) .append(System.currentTimeMillis()).append( "}" ); content.append( "}" ); byte [] msgByte = makebyte(( byte ) 1 , deviceToken, content.toString(), 10000001 ); System.out.println(msgByte); socket.getOutputStream().write(msgByte); socket.getOutputStream().flush(); socket.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 組裝apns規(guī)定的字節(jié)數(shù)組 使用增強(qiáng)型 * * @param command * @param deviceToken * @param payload * @return * @throws IOException */ private static byte [] makebyte( byte command, String deviceToken, String payload, int identifer) { byte [] deviceTokenb = decodeHex(deviceToken); byte [] payloadBytes = null ; ByteArrayOutputStream boas = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(boas); try { payloadBytes = payload.getBytes( "UTF-8" ); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return null ; } try { dos.writeByte(command); dos.writeInt(identifer); //identifer dos.writeInt(Integer.MAX_VALUE); dos.writeShort(deviceTokenb.length); dos.write(deviceTokenb); dos.writeShort(payloadBytes.length); dos.write(payloadBytes); return boas.toByteArray(); } catch (IOException e) { e.printStackTrace(); return null ; } } private static final Pattern pattern = Pattern.compile( "[ -]" ); private static byte [] decodeHex(String deviceToken) { String hex = pattern.matcher(deviceToken).replaceAll( "" ); byte [] bts = new byte [hex.length() / 2 ]; for ( int i = 0 ; i < bts.length; i++) { bts[i] = ( byte ) (charval(hex.charAt( 2 *i)) * 16 + charval(hex.charAt( 2 *i + 1 ))); } return bts; } private static int charval( char a) { if ( '0' <= a && a <= '9' ) return (a - '0' ); else if ( 'a' <= a && a <= 'f' ) return (a - 'a' ) + 10 ; else if ( 'A' <= a && a <= 'F' ) return (a - 'A' ) + 10 ; else { throw new RuntimeException( "Invalid hex character: " + a); } } } |