├── .gitignore ├── .gitmodules ├── .travis.yml ├── README.md ├── android-demo ├── .gitignore ├── 123456.keystore ├── build.gradle ├── google-services.json ├── libs │ ├── HMSSdkBase_2.5.3.305.jar │ ├── HMSSdkPush_2.5.3.305.jar │ ├── MiPush_SDK_Client_3_2_2.jar │ ├── alicloud-android-sdk-httpdns-1.0.7.jar │ ├── armeabi │ │ ├── libcocklogic-1.1.3.so │ │ └── libtnet-3.1.11.so │ ├── com.umeng.message_3.1.1a.jar │ ├── utdid4all-1.1.5.3_proguard.jar │ └── x86 │ │ ├── libcocklogic-1.1.3.so │ │ └── libtnet-3.1.11.so ├── proguard-rules.txt └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── yy │ │ └── misaka │ │ └── demo │ │ ├── TestSocketIO.java │ │ └── util │ │ ├── HttpUtil.java │ │ ├── MyBroadcastReceiver.java │ │ └── TestBase.java │ └── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── java │ └── com │ │ └── yy │ │ └── misaka │ │ └── demo │ │ ├── ChatActivity.java │ │ ├── ConnectActivity.java │ │ ├── DrawActivity.java │ │ ├── DrawView.java │ │ ├── NickNameActivity.java │ │ ├── adapter │ │ └── ChatMessagesAdapter.java │ │ ├── appmodel │ │ ├── DemoApp.java │ │ ├── HttpApi.java │ │ └── YYNotificationReceiver.java │ │ ├── entity │ │ └── Message.java │ │ ├── test │ │ └── TestActivity.java │ │ └── util │ │ ├── HttpUtils.java │ │ └── JsonHelper.java │ └── res │ ├── drawable-xxhdpi │ └── misaka.jpg │ ├── layout │ ├── activity_chat.xml │ ├── activity_connect.xml │ ├── activity_draw.xml │ ├── activity_im_user_list.xml │ ├── activity_login.xml │ ├── activity_main.xml │ ├── activity_nick.xml │ ├── activity_profile.xml │ ├── activity_register.xml │ ├── activity_splash.xml │ ├── activity_test.xml │ ├── item_message.xml │ └── item_user.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── hwpush_colors.xml │ ├── hwpush_strings.xml │ ├── hwpush_styles.xml │ ├── strings.xml │ └── styles.xml ├── android-push-sdk ├── build.gradle ├── libs │ ├── HMSSdkBase_2.5.3.305.jar │ ├── HMSSdkPush_2.5.3.305.jar │ ├── MiPush_SDK_Client_3_2_2.jar │ ├── android.jar │ ├── com.umeng.message_3.1.1a.jar │ ├── firebase-common-11.8.0.jar │ ├── firebase-core-11.8.0.jar │ ├── firebase-iid-11.8.0.jar │ ├── firebase-messaging-11.8.0.jar │ ├── play-services-base-11.8.0.jar │ ├── play-services-basement-11.8.0.jar │ ├── play-services-gcm-11.8.0.jar │ └── support-v4-19.1.0.jar └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── yy │ └── httpproxy │ ├── AndroidLoggingHandler.java │ ├── Config.java │ ├── ProxyClient.java │ ├── requester │ └── RequestInfo.java │ ├── service │ ├── BootBroadcastReceiver.java │ ├── ConnectionService.java │ ├── DefaultDnsHandler.java │ ├── DefaultNotificationHandler.java │ ├── DelegateToClientNotificationHandler.java │ ├── DnsHandler.java │ ├── DummyNotificationHandler.java │ ├── DummyService.java │ ├── ForegroundService.java │ ├── NotificationHandler.java │ ├── NotificationReceiver.java │ └── PushedNotification.java │ ├── socketio │ ├── RemoteClient.java │ └── SocketIOProxyClient.java │ ├── stats │ ├── Connectivity.java │ ├── Performance.java │ └── Stats.java │ ├── subscribe │ ├── CachedSharedPreference.java │ ├── ConnectCallback.java │ ├── PushCallback.java │ ├── PushSubscriber.java │ └── RandomPushIdGenerator.java │ ├── thirdparty │ ├── FirebaseProvider.java │ ├── HuaweiCallback.java │ ├── HuaweiProvider.java │ ├── HuaweiReceiver.java │ ├── MyFirebaseInstanceIdService.java │ ├── MyFirebaseMessagingService.java │ ├── NotificationProvider.java │ ├── ProviderFactory.java │ ├── UmengIntentService.java │ ├── UmengProvider.java │ ├── XiaomiProvider.java │ └── XiaomiReceiver.java │ └── util │ ├── CrashHandler.java │ ├── HttpUtil.java │ ├── JSONUtil.java │ ├── Log.java │ ├── LogcatLogger.java │ ├── Logger.java │ ├── ServiceCheckUtil.java │ ├── SystemProperty.java │ └── Version.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | local.properties 3 | *.iml 4 | node_modules 5 | *.log 6 | dump.rdb 7 | log.txt 8 | pid 9 | pids 10 | pid_debug 11 | .gradle 12 | build 13 | android-push-sdk/secring.gpg 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "android-push-sdk/sub/engine.io-client-java"] 2 | path = android-push-sdk/sub/engine.io-client-java 3 | url = https://github.com/xuduo/engine.io-client-java 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | android: 4 | components: 5 | - build-tools-23.0.1 6 | - android-23 7 | - extra-android-m2repository 8 | - tools 9 | - platform-tools 10 | 11 | script: 12 | - ./gradlew test assembleDebug -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## socket.io-push-android [![Build Status](https://travis-ci.org/xuduo/socket.io-push-android.svg?branch=master)](https://travis-ci.org/xuduo/socket.io-push-android) 2 | demo实现了一个聊天室功能, 编译clone后 需要pull submodule 3 | ``` 4 | git clone https://github.com/xuduo/socket.io-push-android 5 | git submodule update --recursive --remote 6 | ``` 7 | ##### 小米,华为,友盟均为可选接入。开启条件为 对应厂商系统&classpath里有对应sdk&androidManifest里有配置 8 | 9 | 1. 小米推送(所有MUI) MiPush_SDK_Client_XXX.jar 10 | 2. 华为推送(EMUI5.0以上) HMSSdkBase_XXX.jar HMSSdkPush_XXX.jar 11 | 3. 友盟推送(非小米华为) com.umeng.message_XXX.jar alicloud-android-sdk-httpdns-XXX.jar utdid4all-XXX_proguard.jar libcocklogic-XXX.so libtnet-XXX.so 12 | 13 | 14 | ##### 添加maven/gradle依赖 15 | 16 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.yy/android-push-sdk/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.yy/android-push-sdk) 17 | 18 | 19 | maven 20 | ```xml 21 | 22 | com.yy 23 | android-push-sdk 24 | ${version} 25 | 26 | ``` 27 | 28 | 29 | gradle 30 | ```groovy 31 | compile 'com.yy:android-push-sdk:${versoion}' 32 | ``` 33 | 34 | #### AndroidManifest.xml添加receiver,service,permission 35 | 参见Demo的[AndroidManifest.xml](android-demo/src/main/AndroidManifest.xml) 36 | 37 | #### Proguard 38 | 39 | 混淆配置 40 | ``` 41 | -dontwarn com.yy.httpproxy.thirdparty.** 42 | -dontwarn okio.** 43 | 44 | ##如接入华为push 45 | -keep class com.huawei.android.pushagent.** {*;} 46 | -keep class com.huawei.android.pushselfshow.** {*;} 47 | -keep class com.huawei.android.microkernel.** {*;} 48 | -keep class com.baidu.mapapi.** {*;} 49 | -dontwarn com.huawei.** 50 | ##如接入华为push 51 | 52 | 53 | ``` 54 | 55 | ##### 初始化ProxyClient 56 | 每次UI进程启动需要初始化,初始化后会自动启动push进程. 57 | 58 | ```java 59 | Proxy proxyClient = new ProxyClient(new Config(this) 60 | .setHost("http://spush.yy.com") //连接的服务器地址 61 | .setConnectCallback(this) //socket.io通道,连上,断开回调 62 | .setPushCallback(this) //push回调,socket.io长连接通道 63 | .setLogger(MyLogger.class)); //日志回调,可选,这个类会实例化在push进程 64 | ``` 65 | 注意不要通过其他进程启动,可以用以下代码判断是否ui进程 66 | ```java 67 | private boolean isUiProcess() { 68 | ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)); 69 | List processInfos = am.getRunningAppProcesses(); 70 | String mainProcessName = getPackageName(); 71 | int myPid = Process.myPid(); 72 | for (RunningAppProcessInfo info : processInfos) { 73 | if (info.pid == myPid && mainProcessName.equals(info.processName)) { 74 | return true; 75 | } 76 | } 77 | return false; 78 | } 79 | ``` 80 | 81 | 82 | ##### 获取pushId 83 | 84 | 由客户端自动生成, proxyClient实例化后即可获得 85 | 86 | 用于服务器对单个设备发push/notification 87 | ```java 88 | String pushId = proxyClient.getPushId(); 89 | ``` 90 | 91 | 92 | 93 | #### subscribe/unsbuscribe topic 94 | 95 | 调用不需考虑当时是否连线, 重连也不需要重新sub/unsub,sdk里已经处理 96 | ```java 97 | proxyClient.subscribeBroadcast("aTopic"); //对于某个topic的push,需要客户端主动订阅,才能收到.如demo中,需订阅"chatRoom" topic,才能收到聊天消息 98 | proxyClient.subscribeAndReceiveTtlPackets("aTopic"); //同上,这个方法会接收服务器的重传 99 | proxyClient.unsubscribeBroadcast("aTopic"); 100 | ``` 101 | 102 | 103 | 104 | #### 接收push 105 | ```java 106 | public interface PushCallback { 107 | 108 | /** 109 | * 110 | * @param data 服务器push下来的字符串 111 | */ 112 | void onPush(String data); 113 | } 114 | ``` 115 | 116 | 117 | #### 接收notification(使用DefaultNotificationHandler/DelegateToClientNotificationHandler) 118 | sdk默认会弹出系统通知 119 | arrive和click后会调用receiver的方法 120 | ```java 121 | public class YYNotificationReceiver extends NotificationReceiver { 122 | 123 | @Override 124 | public void onNotificationClicked(Context context, PushedNotification notification) { 125 | Log.d("YYNotificationReceiver", "onNotificationClicked " + notification.id + " values " + notification.values); 126 | Toast.makeText(context, "YYNotificationReceiver clicked payload: " + notification.values.get("payload"), Toast.LENGTH_SHORT).show(); 127 | Intent intent = new Intent(context, DrawActivity.class); 128 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 129 | context.startActivity(intent); 130 | } 131 | 132 | /** 133 | * 如果使用DelegateToClientNotificationHandler ,UI进程存活的时候,会调用此方法,不弹出通知. 134 | * UI进程被杀,push进程存活的时候,使用默认的样式弹出 135 |     *  使用小米华为推送时,不会调用 136 |     */ 137 | @Override 138 | public void onNotificationArrived(Context context, PushedNotification notification) { 139 | Log.d("YYNotificationReceiver", "onNotificationArrived " + notification.id + " values " + notification.values); 140 | } 141 | 142 | } 143 | ``` 144 | 启动时的配置,配置使用 145 | ```java 146 | config.setNotificationHandler(MyHandlerClass.class); //不能混淆这个类 147 | ``` 148 | 149 | 150 | #### 自定义弹出通知(使用自定义NotificationHandler) 151 | 可以用代码根据业务服务器下发的notification中的自定义payload字段,展示不同的效果 152 | 153 | 注意!NotificationHandler的实例,是在push进程中的! 154 | 155 | 实现接口 156 | ```java 157 | public interface NotificationHandler { 158 | /** 159 | * 160 | * @param context context 161 | * @param binded UI进程 是否存活 162 | * @param notification 业务服务器下发的notification 163 | */ 164 | void handlerNotification(Context context, boolean binded, PushedNotification notification); 165 | 166 | } 167 | ``` 168 | 启动时的配置,设置NotificationHandler 169 | ```java 170 | config.setNotificationHandler("yourFullyQualifiedHandlerClassName"); //不能混淆这个类 171 | ``` 172 | 173 | #### 绑定UID 174 | 绑定UID是业务服务器调用push-server接口进行绑定的(pushId - uid)的关系 175 | 176 | 由于安全性的问题,客户端无法直接绑定 177 | 178 | push-server和业务服务器的绑定关系可能会不一致 179 | 180 | 每次连接到push-sever后, 客户端要根据回调, 判断回调的uid与当前用户uid是否一致, 进行绑定/解绑 181 | ```java 182 | public interface ConnectCallback { 183 | 184 | /** 185 | * 186 | * @param uid 连接push-server后,在服务器绑定的uid,如未绑定,uid = "" 187 | * @param uid 连接push-server后,在服务器绑定的tags 188 | */ 189 | void onConnect(String uid, Set tags); 190 | 191 | void onDisconnect(); 192 | 193 | } 194 | ``` 195 | 解绑Uid,客户端直接调用接口解绑 196 | ```java 197 | proxyClient.unbindUid(); 198 | ``` 199 | 200 | ##### 添加删除tag 201 | 202 | ```java 203 | proxyClient.addTag("tag1"); 204 | proxyClient.removeTag("tag2"); 205 | ``` 206 | 207 | tag回调同上 208 | 209 | 210 | #### 集成小米push 211 | 212 | 213 | [华为push官方接入文档](http://dev.xiaomi.com/doc/?page_id=1670) 214 | 215 | 本系统透明集成了小米push,开启方法. 216 | 217 | 218 | 1. 添加小米push jar依赖 219 | 2. AndroidManifest.xml配置了小米push相关配置,参见demo 220 | 3. 当前手机运行MiUi系统 221 | 222 | 注意项 223 | 224 | 1. SDK会自动上报小米的regId,并不需要业务代码改动 225 | 2. 对于开启的手机,无法使用自定义NotificationHandler控制notification弹出 226 | 3. 可以通过push-server配置,应用在前台的时候,不弹出通知(小米push功能) 227 | 228 | 229 | 230 | #### 集成华为push 231 | 232 | [华为push官方接入文档](http://developer.huawei.com/push) 233 | 234 | 本系统透明集成了华为push,开启方法 235 | 236 | 1. 添加华为push jar依赖,拷贝一堆资源文件(华为push自带) 237 | 2. AndroidManifest.xml配置了华为push相关配置,参见demo 238 | 3. 当前手机运行华为系统 239 | 240 | 注意项 241 | 242 | 1. SDK会自动上报华为的token,并不需要业务代码改动 243 | 2. 对于开启的手机,无法使用自定义NotificationHandler控制notification弹出 244 | 245 | 246 | #### UI进程单独使用push功能 247 | 248 | ```java 249 | String pushId = new RandomPushIdGenerator().generatePushId(pushId); //生成随机pushId 250 | SocketIOProxyClient client = new SocketIOProxyClient(this.getApplicationContext(), host, null); 251 | client.setPushId(pushId); //设置pushId 252 | client.setPushCallback(this); // push回调 253 | client.setNotificationCallback(this); //notification回调 254 | client.setConnectCallback(this); //连接回调 255 | ``` 256 | -------------------------------------------------------------------------------- /android-demo/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /android-demo/123456.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/123456.keystore -------------------------------------------------------------------------------- /android-demo/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | 4 | android { 5 | compileSdkVersion 23 6 | buildToolsVersion "23.0.1" 7 | 8 | signingConfigs { 9 | release { 10 | storeFile file("123456.keystore") 11 | storePassword "123456" 12 | keyAlias "123456" 13 | keyPassword "123456" 14 | } 15 | 16 | debug { 17 | storeFile file("123456.keystore") 18 | storePassword "123456" 19 | keyAlias "123456" 20 | keyPassword "123456" 21 | } 22 | 23 | } 24 | 25 | defaultConfig { 26 | minSdkVersion 15 27 | targetSdkVersion 22 28 | versionCode 1 29 | versionName "1.0" 30 | applicationId "com.yy.misaka.demo" 31 | } 32 | buildTypes { 33 | release { 34 | minifyEnabled true 35 | signingConfig signingConfigs.release 36 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' 37 | } 38 | } 39 | lintOptions { 40 | abortOnError false 41 | } 42 | dexOptions { 43 | incremental true 44 | } 45 | compileOptions { 46 | sourceCompatibility JavaVersion.VERSION_1_7 47 | targetCompatibility JavaVersion.VERSION_1_7 48 | } 49 | 50 | sourceSets { 51 | main { 52 | jniLibs.srcDirs = ['libs'] 53 | } 54 | } 55 | } 56 | 57 | dependencies { 58 | compile fileTree(include: ['*.jar'], dir: 'libs') 59 | compile project(':android-push-sdk') 60 | compile 'com.android.support:appcompat-v7:19.+' 61 | compile 'com.google.code.gson:gson:2.4' 62 | compile 'com.android.support:recyclerview-v7:21.+' 63 | compile 'com.android.support:multidex:1.0.0' 64 | compile 'com.google.firebase:firebase-core:11.8.0' //接入GCM才需要 65 | compile 'com.google.firebase:firebase-messaging:11.8.0' //接入GCM才需要 66 | compile 'com.google.android.gms:play-services-base:11.8.0' //接入GCM才需要 67 | } 68 | 69 | apply plugin: 'com.google.gms.google-services' //接入GCM才需要, 并需要从后台下载google-services.json -------------------------------------------------------------------------------- /android-demo/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "478153921873", 4 | "firebase_url": "https://socketiodemo.firebaseio.com", 5 | "project_id": "socketiodemo", 6 | "storage_bucket": "socketiodemo.appspot.com" 7 | }, 8 | "client": [ 9 | { 10 | "client_info": { 11 | "mobilesdk_app_id": "1:478153921873:android:163250854d1c81d9", 12 | "android_client_info": { 13 | "package_name": "com.yy.misaka.demo" 14 | } 15 | }, 16 | "oauth_client": [ 17 | { 18 | "client_id": "478153921873-k4vc1uogcfsvmv2skhjat9mhf7r4ir0n.apps.googleusercontent.com", 19 | "client_type": 3 20 | } 21 | ], 22 | "api_key": [ 23 | { 24 | "current_key": "AIzaSyAsgGvo1gDNF8aczl3GoxpYVhl1luoxn5Q" 25 | } 26 | ], 27 | "services": { 28 | "analytics_service": { 29 | "status": 1 30 | }, 31 | "appinvite_service": { 32 | "status": 1, 33 | "other_platform_oauth_client": [] 34 | }, 35 | "ads_service": { 36 | "status": 2 37 | } 38 | } 39 | } 40 | ], 41 | "configuration_version": "1" 42 | } -------------------------------------------------------------------------------- /android-demo/libs/HMSSdkBase_2.5.3.305.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/libs/HMSSdkBase_2.5.3.305.jar -------------------------------------------------------------------------------- /android-demo/libs/HMSSdkPush_2.5.3.305.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/libs/HMSSdkPush_2.5.3.305.jar -------------------------------------------------------------------------------- /android-demo/libs/MiPush_SDK_Client_3_2_2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/libs/MiPush_SDK_Client_3_2_2.jar -------------------------------------------------------------------------------- /android-demo/libs/alicloud-android-sdk-httpdns-1.0.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/libs/alicloud-android-sdk-httpdns-1.0.7.jar -------------------------------------------------------------------------------- /android-demo/libs/armeabi/libcocklogic-1.1.3.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/libs/armeabi/libcocklogic-1.1.3.so -------------------------------------------------------------------------------- /android-demo/libs/armeabi/libtnet-3.1.11.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/libs/armeabi/libtnet-3.1.11.so -------------------------------------------------------------------------------- /android-demo/libs/com.umeng.message_3.1.1a.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/libs/com.umeng.message_3.1.1a.jar -------------------------------------------------------------------------------- /android-demo/libs/utdid4all-1.1.5.3_proguard.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/libs/utdid4all-1.1.5.3_proguard.jar -------------------------------------------------------------------------------- /android-demo/libs/x86/libcocklogic-1.1.3.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/libs/x86/libcocklogic-1.1.3.so -------------------------------------------------------------------------------- /android-demo/libs/x86/libtnet-3.1.11.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/libs/x86/libtnet-3.1.11.so -------------------------------------------------------------------------------- /android-demo/proguard-rules.txt: -------------------------------------------------------------------------------- 1 | -keep class com.huawei.android.pushagent.** {*;} 2 | -keep class com.huawei.android.pushselfshow.** {*;} 3 | -keep class com.huawei.android.microkernel.** {*;} 4 | -keep class com.baidu.mapapi.** {*;} 5 | 6 | -dontwarn com.yy.httpproxy.thirdparty.** 7 | -dontwarn okio.** 8 | 9 | -dontwarn com.taobao.** 10 | -dontwarn anet.channel.** 11 | -dontwarn anetwork.channel.** 12 | -dontwarn org.android.** 13 | -dontwarn com.xiaomi.** 14 | -dontwarn com.huawei.** 15 | -dontwarn org.apache.thrift.** 16 | 17 | -keepattributes *Annotation* 18 | 19 | -keep class com.taobao.** {*;} 20 | -keep class org.android.** {*;} 21 | -keep class anet.channel.** {*;} 22 | -keep class com.umeng.** {*;} 23 | -keep class com.xiaomi.** {*;} 24 | -keep class com.huawei.** {*;} 25 | -keep class org.apache.thrift.** {*;} 26 | -keep class com.alibaba.sdk.android.**{*;} 27 | -keep class com.ut.**{*;} 28 | -keep class com.ta.**{*;} 29 | 30 | -keep public class com.umeng.message.example.example.R$*{ 31 | public static final int *; 32 | } 33 | 34 | #避免log打印输出 35 | -assumenosideeffects class android.util.Log { 36 | public static *** v(...); 37 | public static *** d(...); 38 | public static *** i(...); 39 | public static *** w(...); 40 | } 41 | 42 | -ignorewarning 43 | -keepattributes Exceptions 44 | -keepattributes InnerClasses 45 | -keepattributes Signature 46 | -keepattributes SourceFile,LineNumberTable 47 | -keep class com.hianalytics.android.**{*;} 48 | -keep class com.huawei.updatesdk.**{*;} 49 | -keep class com.huawei.hms.**{*;} -------------------------------------------------------------------------------- /android-demo/src/androidTest/java/com/yy/misaka/demo/TestSocketIO.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo; 2 | 3 | import android.util.Log; 4 | 5 | import com.yy.misaka.demo.test.TestActivity; 6 | import com.yy.misaka.demo.util.MyBroadcastReceiver; 7 | import com.yy.misaka.demo.util.TestBase; 8 | 9 | import java.io.IOException; 10 | import java.util.concurrent.CountDownLatch; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | import okhttp3.Call; 14 | import okhttp3.Callback; 15 | import okhttp3.Response; 16 | 17 | /** 18 | * Created by Administrator on 2016/7/26. 19 | */ 20 | public class TestSocketIO extends TestBase { 21 | public final static String TAG = "TestSocketIO"; 22 | private String pushData = "Hello World"; 23 | private int timeOut = 10; 24 | 25 | public void testInit() throws InterruptedException { 26 | final CountDownLatch signal = new CountDownLatch(1); 27 | assertNotNull(mActivity); 28 | mActivity.setConnectCallBack(new TestActivity.TestConnectCallBack() { 29 | @Override 30 | public void isConnect(boolean state) { 31 | assertEquals(state, true); 32 | signal.countDown(); 33 | } 34 | }); 35 | boolean resutl = signal.await(timeOut, TimeUnit.SECONDS); 36 | assertEquals(resutl, true);//timeout return false 37 | } 38 | 39 | public void testPushByTopic() throws InterruptedException { 40 | pushTest(true); 41 | } 42 | 43 | public void testPushByPushId() throws InterruptedException { 44 | pushTest(false); 45 | } 46 | 47 | public void testNotification() throws InterruptedException { 48 | final CountDownLatch signal = new CountDownLatch(2); 49 | httpUtil.asyncGet(httpUtil.getNotificationUrl(mActivity.host, mActivity.pushId), new Callback() { 50 | @Override 51 | public void onFailure(Call call, IOException e) { 52 | 53 | } 54 | 55 | @Override 56 | public void onResponse(Call call, Response response) throws IOException { 57 | assertEquals(response.body().string(), httpResult); 58 | signal.countDown(); 59 | } 60 | }); 61 | myBroadcastReceiver.setNotificationCallBack(new MyBroadcastReceiver.TestNotificationCallBack() { 62 | @Override 63 | public void onNotification(String title, String message, String payload) { 64 | assertEquals(title, "title"); 65 | assertEquals(message, "message"); 66 | signal.countDown(); 67 | } 68 | }); 69 | boolean resutl = signal.await(timeOut, TimeUnit.SECONDS); 70 | assertEquals(resutl, true); 71 | } 72 | 73 | private void pushTest(boolean isTopic) throws InterruptedException{ 74 | String url = httpUtil.getPushUrlByPushId(mActivity.host, pushData, mActivity.pushId); 75 | if (isTopic) { 76 | url = httpUtil.getPushUrlByTopic(mActivity.host, pushData, mActivity.topic); 77 | } 78 | final CountDownLatch signal = new CountDownLatch(2); 79 | httpUtil.asyncGet(url, new Callback() { 80 | @Override 81 | public void onFailure(Call call, IOException e) { 82 | 83 | } 84 | 85 | @Override 86 | public void onResponse(Call call, Response response) throws IOException { 87 | assertEquals(response.body().string(), httpResult); 88 | signal.countDown(); 89 | } 90 | }); 91 | 92 | mActivity.setPushCallBack(new TestActivity.TestPushCallBack() { 93 | @Override 94 | public void onPush(String data) { 95 | Log.i(TAG, "onPush: " + data); 96 | assertEquals(data, pushData); 97 | signal.countDown(); 98 | } 99 | }); 100 | boolean resutl = signal.await(timeOut, TimeUnit.SECONDS); 101 | assertEquals(resutl, true); 102 | } 103 | 104 | 105 | } 106 | -------------------------------------------------------------------------------- /android-demo/src/androidTest/java/com/yy/misaka/demo/util/HttpUtil.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo.util; 2 | 3 | import okhttp3.Callback; 4 | import okhttp3.OkHttpClient; 5 | import okhttp3.Request; 6 | 7 | /** 8 | * Created by Administrator on 2016/7/26. 9 | */ 10 | public class HttpUtil { 11 | 12 | private OkHttpClient okHttpClient = new OkHttpClient(); 13 | 14 | public void asyncGet(String requestUrl, Callback callback) { 15 | final Request request = new Request.Builder().url(requestUrl).build(); 16 | okHttpClient.newCall(request).enqueue(callback); 17 | } 18 | 19 | public String getPushUrlByTopic(String host, String pushData, String topic) { 20 | return host + "/api/push?json=" + pushData + "&topic=" + topic; 21 | } 22 | 23 | public String getPushUrlByPushId(String host, String pushData, String pushId) { 24 | return host + "/api/push?json=" + pushData + "&pushId=" + pushId; 25 | } 26 | 27 | public String getNotificationUrl(String host, String pushId) { 28 | return host + "/api/notification?pushId=" + pushId 29 | + "¬ification=%7B%20%22android%22%3A%7B%22title%22%3A%22title%22%2C%22message%22%3A%22message%22%7D%2C%22apn%22%3A%7B%22alert%22%3A%22message%22%20%2C%20%22badge%22%3A5%2C%20%22sound%22%3A%22default%22%2C%20%22payload%22%3A1234%7D%7D"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /android-demo/src/androidTest/java/com/yy/misaka/demo/util/MyBroadcastReceiver.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo.util; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.util.Log; 7 | 8 | /** 9 | * Created by Administrator on 2016/7/26. 10 | */ 11 | public class MyBroadcastReceiver extends BroadcastReceiver { 12 | 13 | private TestNotificationCallBack notificationCallBack; 14 | 15 | public void setNotificationCallBack(TestNotificationCallBack notificationCallBack) { 16 | this.notificationCallBack = notificationCallBack; 17 | } 18 | 19 | @Override 20 | public void onReceive(Context context, Intent intent) { 21 | String title = intent.getStringExtra("title"); 22 | String message = intent.getStringExtra("message"); 23 | String payload = intent.getStringExtra("payload"); 24 | notificationCallBack.onNotification(title, message, payload); 25 | } 26 | 27 | public interface TestNotificationCallBack { 28 | void onNotification(String title, String message, String payload); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /android-demo/src/androidTest/java/com/yy/misaka/demo/util/TestBase.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo.util; 2 | 3 | import android.content.Intent; 4 | import android.content.IntentFilter; 5 | import android.test.InstrumentationTestCase; 6 | 7 | import com.yy.misaka.demo.test.TestActivity; 8 | 9 | /** 10 | * Created by Administrator on 2016/7/22. 11 | */ 12 | public class TestBase extends InstrumentationTestCase { 13 | 14 | public TestActivity mActivity; 15 | public String httpResult = "{\"code\":\"success\"}"; 16 | public HttpUtil httpUtil = new HttpUtil(); 17 | public MyBroadcastReceiver myBroadcastReceiver; 18 | 19 | @Override 20 | protected void setUp() throws Exception { 21 | super.setUp(); 22 | Intent intent = new Intent(); 23 | intent.setClassName("com.yy.misaka.demo", TestActivity.class.getName()); 24 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 25 | mActivity = (TestActivity) getInstrumentation().startActivitySync(intent); 26 | 27 | if (getName().equals("testNotification")) { 28 | myBroadcastReceiver = new MyBroadcastReceiver(); 29 | IntentFilter filter = new IntentFilter(); 30 | filter.addAction("com.yy.misaka.demo.YY_NOTIFICATION"); 31 | mActivity.registerReceiver(myBroadcastReceiver, filter); 32 | } 33 | } 34 | 35 | @Override 36 | protected void tearDown() { 37 | if (getName().equals("testNotification")) { 38 | mActivity.unregisterReceiver(myBroadcastReceiver); 39 | } 40 | mActivity.finish(); 41 | try { 42 | super.tearDown(); 43 | } catch (Exception e) { 44 | e.printStackTrace(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /android-demo/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/ChatActivity.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.util.Log; 10 | import android.view.View; 11 | import android.widget.EditText; 12 | 13 | import com.google.gson.Gson; 14 | import com.yy.httpproxy.subscribe.ConnectCallback; 15 | import com.yy.httpproxy.subscribe.PushCallback; 16 | import com.yy.misaka.demo.appmodel.DemoApp; 17 | import com.yy.misaka.demo.adapter.ChatMessagesAdapter; 18 | import com.yy.misaka.demo.entity.Message; 19 | 20 | import java.util.Set; 21 | 22 | public class ChatActivity extends Activity implements ConnectCallback, PushCallback { 23 | public final static String chatTopic = "chatRoom"; 24 | public final static String TAG = "ChatActivity"; 25 | private RecyclerView recyclerViewMessages; 26 | private ChatMessagesAdapter chatMessagesAdapter; 27 | public static final String API_URL = "https://spush.yy.com/api/push"; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | Log.i("DemoLogger", "ChatActivity onCreate"); 33 | setContentView(R.layout.activity_chat); 34 | init(); 35 | 36 | DemoApp.APP_CONTEXT.proxyClient.subscribeAndReceiveTtlPackets(chatTopic); 37 | DemoApp.APP_CONTEXT.proxyClient.getConfig().setPushCallback(this).setConnectCallback(this); 38 | } 39 | 40 | private void init() { 41 | final String nickName = getIntent().getStringExtra("nickName"); 42 | final EditText editTextInput = (EditText) findViewById(R.id.et_input); 43 | findViewById(R.id.btn_send).setOnClickListener(new View.OnClickListener() { 44 | @Override 45 | public void onClick(View v) { 46 | if (String.valueOf(editTextInput.getText()).length() == 0) { 47 | return; 48 | } 49 | Message message = new Message(); 50 | message.setMessage(String.valueOf(editTextInput.getText())); 51 | message.setNickName(nickName); 52 | DemoApp.APP_CONTEXT.httpApi.sendMessage(message, chatTopic, null); 53 | editTextInput.setText(""); 54 | } 55 | }); 56 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ChatActivity.this); 57 | linearLayoutManager.setStackFromEnd(true); 58 | chatMessagesAdapter = new ChatMessagesAdapter(); 59 | recyclerViewMessages = (RecyclerView) findViewById(R.id.rv_messages); 60 | recyclerViewMessages.setLayoutManager(linearLayoutManager); 61 | recyclerViewMessages.setAdapter(chatMessagesAdapter); 62 | recyclerViewMessages.scrollToPosition(chatMessagesAdapter.getItemCount() - 1); 63 | 64 | updateConnect(); 65 | } 66 | 67 | public static void launch(Context context, String nickName) { 68 | Intent intent = new Intent(); 69 | intent.putExtra("nickName", nickName); 70 | intent.setClass(context, ChatActivity.class); 71 | context.startActivity(intent); 72 | } 73 | 74 | @Override 75 | public void onBackPressed() { 76 | super.onBackPressed(); 77 | } 78 | 79 | private void updateConnect() { 80 | String connectState = DemoApp.APP_CONTEXT.proxyClient.isConnected() ? "(connected)" : "(disconnected)"; 81 | setTitle("ChatRoom" + connectState); 82 | } 83 | 84 | @Override 85 | public void onConnect(String uid) { 86 | updateConnect(); 87 | } 88 | 89 | @Override 90 | public void onDisconnect() { 91 | updateConnect(); 92 | } 93 | 94 | @Override 95 | public void onPush(String data) { 96 | Log.i(TAG, "on push " + data); 97 | try { 98 | Message message = new Gson().fromJson(data, Message.class); 99 | if ("chat_message".equals(message.getType())) { 100 | chatMessagesAdapter.addData(message); 101 | recyclerViewMessages.scrollToPosition(chatMessagesAdapter.getItemCount() - 1); 102 | } 103 | } catch (Exception e) { 104 | 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/ConnectActivity.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.widget.EditText; 9 | import android.widget.Toast; 10 | 11 | import com.yy.httpproxy.service.ForegroundService; 12 | import com.yy.httpproxy.subscribe.ConnectCallback; 13 | import com.yy.httpproxy.subscribe.PushCallback; 14 | import com.yy.httpproxy.util.Logger; 15 | 16 | /** 17 | * Created by huangzhilong on 2016/8/31. 18 | */ 19 | public class ConnectActivity extends Activity implements ConnectCallback, PushCallback{ 20 | private EditText editText; 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_connect); 25 | editText = (EditText) findViewById(R.id.et_host); 26 | 27 | findViewById(R.id.btn_connect).setOnClickListener(new View.OnClickListener() { 28 | @Override 29 | public void onClick(View v) { 30 | String host = String.valueOf(editText.getText()).trim(); 31 | } 32 | }); 33 | 34 | findViewById(R.id.btn_foreground_test).setOnClickListener(new View.OnClickListener() { 35 | @Override 36 | public void onClick(View v) { 37 | startForegroundService(); 38 | } 39 | }); 40 | } 41 | 42 | @Override 43 | public void onConnect(String uid) { 44 | Intent intent = new Intent(); 45 | intent.setClass(ConnectActivity.this, NickNameActivity.class); 46 | startActivity(intent); 47 | finish(); 48 | } 49 | 50 | @Override 51 | public void onDisconnect() { 52 | Toast.makeText(this, "Connect Socket failed", Toast.LENGTH_SHORT); 53 | } 54 | 55 | @Override 56 | public void onPush(String data) { 57 | 58 | } 59 | 60 | private void startForegroundService() { 61 | try { 62 | Intent intent = new Intent(this, ForegroundService.class); 63 | startService(intent); 64 | } catch (Exception e) { 65 | com.yy.httpproxy.util.Log.e("", "start ForegroundService error", e); 66 | } 67 | } 68 | 69 | public static class DemoLogger implements Logger { 70 | @Override 71 | public void log(int level, String message, Throwable e) { 72 | Log.d("DemoLogger", "demo " + message, e); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/DrawActivity.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.os.Handler; 7 | import android.util.Log; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.widget.TextView; 11 | 12 | import com.google.gson.Gson; 13 | import com.yy.httpproxy.subscribe.ConnectCallback; 14 | import com.yy.httpproxy.subscribe.PushCallback; 15 | import com.yy.misaka.demo.appmodel.DemoApp; 16 | import com.yy.misaka.demo.appmodel.HttpApi; 17 | 18 | import java.util.Random; 19 | import java.util.Set; 20 | 21 | 22 | public class DrawActivity extends Activity implements ConnectCallback, PushCallback { 23 | 24 | private static final String TAG = "DrawActivity"; 25 | private static String drawTopic = "drawTopic"; 26 | private DrawView drawView; 27 | private TextView latency; 28 | private TextView apiLatency; 29 | private TextView count; 30 | private TextView connect; 31 | private long totalTime; 32 | private long totalCount; 33 | private long totalApiTime; 34 | private long totalApiCount; 35 | public int myColors[] = {Color.BLACK, Color.DKGRAY, Color.CYAN, Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, Color.MAGENTA}; 36 | public int myColor; 37 | private Handler handler = new Handler(); 38 | private HttpApi.CB cb = new HttpApi.CB() { 39 | @Override 40 | public void latency(final long latency) { 41 | handler.post(new Runnable() { 42 | @Override 43 | public void run() { 44 | updateApiLatency(latency); 45 | } 46 | }); 47 | } 48 | }; 49 | 50 | private void updateLatency(long timestamp) { 51 | totalTime += System.currentTimeMillis() - timestamp; 52 | totalCount++; 53 | latency.setText("all:" + (totalTime / totalCount) + "ms"); 54 | count.setText(totalCount + "dots"); 55 | } 56 | 57 | 58 | private void updateApiLatency(long latency) { 59 | totalApiTime += latency; 60 | totalApiCount++; 61 | apiLatency.setText("api:" + (totalApiTime / totalApiCount) + "ms"); 62 | } 63 | 64 | private void resetLatency() { 65 | totalCount = 0; 66 | totalTime = 0; 67 | totalApiCount = 0; 68 | totalApiTime = 0; 69 | latency.setText("0ms"); 70 | apiLatency.setText("0ms"); 71 | count.setText("0dots"); 72 | } 73 | 74 | @Override 75 | protected void onCreate(Bundle savedInstanceState) { 76 | super.onCreate(savedInstanceState); 77 | Log.i("DemoLogger", "DrawActivity onCreate"); 78 | setContentView(R.layout.activity_draw); 79 | latency = (TextView) findViewById(R.id.tv_latency); 80 | apiLatency = (TextView) findViewById(R.id.tv_api_latency); 81 | count = (TextView) findViewById(R.id.tv_count); 82 | connect = (TextView) findViewById(R.id.tv_connect); 83 | drawView = (DrawView) findViewById(R.id.draw_view); 84 | DemoApp.APP_CONTEXT.proxyClient.getConfig().setConnectCallback(this); 85 | DemoApp.APP_CONTEXT.proxyClient.getConfig().setPushCallback(this); 86 | DemoApp.APP_CONTEXT.proxyClient.subscribeBroadcast(drawTopic); 87 | updateConnect(); 88 | 89 | Random random = new Random(); 90 | myColor = myColors[random.nextInt(myColors.length)]; 91 | 92 | drawView.setOnTouchListener(new View.OnTouchListener() { 93 | @Override 94 | public boolean onTouch(View view, MotionEvent event) { 95 | DrawView.Dot dot = new DrawView.Dot(); 96 | dot.xPercent = event.getX() / view.getWidth(); 97 | dot.yPercent = event.getY() / view.getHeight(); 98 | dot.setIntColor(myColor); 99 | Log.d(TAG, "onTouch " + dot); 100 | if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { 101 | DemoApp.APP_CONTEXT.httpApi.sendMessage(dot, drawTopic, cb); 102 | return true; 103 | } else if (event.getAction() == MotionEvent.ACTION_UP) { 104 | dot.endline = true; 105 | DemoApp.APP_CONTEXT.httpApi.sendMessage(dot, drawTopic, cb); 106 | return true; 107 | } else { 108 | return false; 109 | } 110 | } 111 | }); 112 | 113 | findViewById(R.id.btn_clear).setOnClickListener(new View.OnClickListener() { 114 | @Override 115 | public void onClick(View v) { 116 | DemoApp.APP_CONTEXT.httpApi.sendMessage(new DrawView.Dot(), drawTopic, null); 117 | resetLatency(); 118 | } 119 | }); 120 | } 121 | 122 | 123 | private void updateConnect() { 124 | connect.setText(DemoApp.APP_CONTEXT.proxyClient.isConnected() ? "connected" : "disconnected"); 125 | } 126 | 127 | @Override 128 | public void onConnect(String uid) { 129 | updateConnect(); 130 | } 131 | 132 | @Override 133 | public void onDisconnect() { 134 | updateConnect(); 135 | } 136 | 137 | @Override 138 | public void onPush(String data) { 139 | Log.d(TAG, "push " + data); 140 | DrawView.Dot dot = new Gson().fromJson(data, DrawView.Dot.class); 141 | if (dot.xPercent == 0 && dot.yPercent == 0) { 142 | drawView.clear(); 143 | return; 144 | } 145 | drawView.addDot(dot); 146 | updateLatency(dot.timestamp); 147 | } 148 | } -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/DrawView.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | import com.yy.httpproxy.util.Log; 12 | 13 | import java.util.ArrayList; 14 | import java.util.HashMap; 15 | import java.util.Iterator; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | public class DrawView extends View { 20 | 21 | public static class Dot { 22 | private static int ID = (int) (Math.random() * 1000000); 23 | 24 | public float xPercent; 25 | public float yPercent; 26 | public String color; 27 | public int id = ID; 28 | public long timestamp = System.currentTimeMillis(); 29 | public boolean endline = false; 30 | 31 | @Override 32 | public String toString() { 33 | return "Dot{" + 34 | "xPercent=" + xPercent + 35 | ", yPercent=" + yPercent + 36 | ", myColor=" + color + 37 | ", timestamp=" + timestamp + 38 | ", endline=" + endline + 39 | '}'; 40 | } 41 | 42 | public void setIntColor(int intColor) { 43 | color = String.format("%06X", (0xFFFFFF & intColor)); 44 | } 45 | } 46 | 47 | private Map> lineMap = new HashMap<>(); 48 | 49 | public DrawView(Context context) { 50 | super(context); 51 | } 52 | 53 | public DrawView(Context context, AttributeSet attrs) { 54 | super(context, attrs); 55 | } 56 | 57 | public DrawView(Context context, AttributeSet attrs, int defStyle) { 58 | super(context, attrs, defStyle); 59 | } 60 | 61 | @Override 62 | protected void onDraw(Canvas canvas) { 63 | super.onDraw(canvas); 64 | 65 | Log.i("drawview", "ondraw"); 66 | Paint paint = new Paint(); 67 | 68 | paint.setStyle(Paint.Style.STROKE); 69 | paint.setStrokeWidth(6); 70 | for (List dots : lineMap.values()) { 71 | Path path = new Path(); 72 | boolean first = true; 73 | for (Dot dot : dots) { 74 | float x = dot.xPercent * canvas.getWidth(); 75 | float y = dot.yPercent * canvas.getHeight(); 76 | paint.setColor(Color.parseColor("#" + dot.color)); 77 | if (first) { 78 | first = false; 79 | path.moveTo(x, y); 80 | } else if (dot.endline) { 81 | path.lineTo(x, y); 82 | canvas.drawPath(path, paint); 83 | first = true; 84 | } else { 85 | path.lineTo(x, y); 86 | } 87 | } 88 | if (!first) { 89 | canvas.drawPath(path, paint); 90 | } 91 | } 92 | } 93 | 94 | public void addDot(Dot dot) { 95 | List lines = lineMap.get(dot.id); 96 | if (lines == null) { 97 | lines = new ArrayList<>(); 98 | lineMap.put(dot.id, lines); 99 | } 100 | lines.add(dot); 101 | invalidate(); 102 | } 103 | 104 | public void clear() { 105 | lineMap.clear(); 106 | invalidate(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/NickNameActivity.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.EditText; 8 | import android.widget.Toast; 9 | 10 | import android.util.Log; 11 | 12 | import com.yy.httpproxy.thirdparty.FirebaseProvider; 13 | import com.yy.httpproxy.thirdparty.ProviderFactory; 14 | 15 | import java.util.Arrays; 16 | 17 | public class NickNameActivity extends Activity { 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | if (FirebaseProvider.handleLauncher(this)) { 23 | finish(); 24 | return; 25 | } 26 | setContentView(R.layout.activity_nick); 27 | String provider = "socket.io"; 28 | if (ProviderFactory.checkProvider(this) != null) { 29 | provider = ProviderFactory.checkProvider(this).getSimpleName(); 30 | } 31 | setTitle("NotificationProvider :" + provider); 32 | init(); 33 | } 34 | 35 | private void init() { 36 | final EditText etNickName = (EditText) findViewById(R.id.et_nick_nickname); 37 | 38 | findViewById(R.id.btn_nick_enter).setOnClickListener(new View.OnClickListener() { 39 | @Override 40 | public void onClick(View v) { 41 | String nickname = String.valueOf(etNickName.getText()).trim(); 42 | if (nickname.equals("")) { 43 | Toast.makeText(NickNameActivity.this, "Nickname can't be null", Toast.LENGTH_SHORT).show(); 44 | } else { 45 | ChatActivity.launch(NickNameActivity.this, nickname); 46 | } 47 | } 48 | }); 49 | 50 | findViewById(R.id.btn_draw_enter).setOnClickListener(new View.OnClickListener() { 51 | @Override 52 | public void onClick(View v) { 53 | Intent intent = new Intent(); 54 | intent.setClass(NickNameActivity.this, DrawActivity.class); 55 | startActivity(intent); 56 | } 57 | }); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/adapter/ChatMessagesAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo.adapter; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.support.v7.widget.RecyclerView.ViewHolder; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import com.yy.misaka.demo.R; 11 | import com.yy.misaka.demo.entity.Message; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | 17 | public class ChatMessagesAdapter extends RecyclerView.Adapter { 18 | 19 | private List messagesList; 20 | 21 | public void addData(Message message) { 22 | messagesList.add(message); 23 | notifyDataSetChanged(); 24 | } 25 | 26 | public ChatMessagesAdapter() { 27 | messagesList = new ArrayList<>(); 28 | } 29 | 30 | static class MyViewHolder extends ViewHolder { 31 | 32 | TextView textViewNickName; 33 | TextView textViewMessage; 34 | View itemView; 35 | 36 | public MyViewHolder(View itemView) { 37 | super(itemView); 38 | this.itemView=itemView; 39 | textViewNickName = (TextView) itemView.findViewById(R.id.tv_nickname); 40 | textViewMessage = (TextView) itemView.findViewById(R.id.tv_message); 41 | } 42 | } 43 | 44 | @Override 45 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 46 | View view = LayoutInflater.from(parent.getContext()) 47 | .inflate(R.layout.item_message, parent, false); 48 | return new MyViewHolder(view); 49 | } 50 | 51 | @Override 52 | public void onBindViewHolder(MyViewHolder holder, int position) { 53 | holder.textViewNickName.setText(messagesList.get(position).getNickName() + ": "); 54 | holder.textViewMessage.setText( messagesList.get(position).getMessage()); 55 | holder.itemView.setTag(position); 56 | } 57 | 58 | @Override 59 | public int getItemCount() { 60 | return messagesList.size(); 61 | } 62 | 63 | } 64 | 65 | -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/appmodel/DemoApp.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo.appmodel; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | 6 | import com.yy.httpproxy.Config; 7 | import com.yy.httpproxy.ProxyClient; 8 | import com.yy.httpproxy.service.DefaultDnsHandler; 9 | import com.yy.httpproxy.service.DefaultNotificationHandler; 10 | import com.yy.misaka.demo.ChatActivity; 11 | import com.yy.misaka.demo.ConnectActivity; 12 | 13 | 14 | /** 15 | * Created by xuduo on 6/13/16. 16 | */ 17 | public class DemoApp extends Application { 18 | 19 | public static DemoApp APP_CONTEXT; 20 | public ProxyClient proxyClient; 21 | public HttpApi httpApi; 22 | private String host = "https://spush.yy.com"; 23 | 24 | @Override 25 | public void onCreate() { 26 | Log.i("DemoLogger", "DemoApp onCreate"); 27 | super.onCreate(); 28 | APP_CONTEXT = this; 29 | httpApi = new HttpApi(ChatActivity.API_URL); 30 | DemoApp.APP_CONTEXT.proxyClient = new ProxyClient(new Config(DemoApp.APP_CONTEXT).setHost(host) 31 | .setNotificationHandler(DefaultNotificationHandler.class) 32 | .setDnsHandler(DefaultDnsHandler.class) 33 | .setLogger(ConnectActivity.DemoLogger.class)); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/appmodel/HttpApi.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo.appmodel; 2 | 3 | import android.util.Log; 4 | 5 | import com.yy.httpproxy.ProxyClient; 6 | import com.yy.misaka.demo.ChatActivity; 7 | import com.yy.misaka.demo.entity.Message; 8 | import com.yy.misaka.demo.util.HttpUtils; 9 | import com.yy.misaka.demo.util.JsonHelper; 10 | 11 | import java.io.IOException; 12 | import java.util.HashMap; 13 | 14 | import okhttp3.Call; 15 | import okhttp3.Callback; 16 | import okhttp3.Response; 17 | 18 | public class HttpApi { 19 | private String url; 20 | private static final String TAG = "HttpApi"; 21 | 22 | public interface CB { 23 | void latency(long latency); 24 | } 25 | 26 | public HttpApi(String url) { 27 | this.url = url; 28 | } 29 | 30 | public void sendMessage(Object msg, String topic,final CB cb) { 31 | HashMap params = new HashMap<>(); 32 | String msgStr = JsonHelper.toJson(msg, "UTF-8"); 33 | Log.d(TAG, "msgStr " + msgStr); 34 | params.put("json", msgStr); 35 | params.put("topic", topic); 36 | final long start = System.currentTimeMillis(); 37 | HttpUtils.request(url, params, new Callback() { 38 | @Override 39 | public void onFailure(Call call, IOException e) { 40 | Log.d(TAG, "sendMessage onFailure"); 41 | } 42 | 43 | @Override 44 | public void onResponse(Call call, Response response) throws IOException { 45 | Log.d(TAG, "sendMessage onResponse " + " p: " + response.protocol() + " " + response.body().string()); 46 | if (cb != null) { 47 | cb.latency(System.currentTimeMillis() - start); 48 | } 49 | } 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/appmodel/YYNotificationReceiver.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo.appmodel; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.util.Log; 6 | import android.widget.Toast; 7 | 8 | import com.yy.httpproxy.service.DefaultNotificationHandler; 9 | import com.yy.httpproxy.service.NotificationReceiver; 10 | import com.yy.httpproxy.service.PushedNotification; 11 | import com.yy.misaka.demo.DrawActivity; 12 | 13 | import java.util.HashMap; 14 | 15 | /** 16 | * Created by xuduo on 11/6/15. 17 | */ 18 | public class YYNotificationReceiver extends NotificationReceiver { 19 | 20 | @Override 21 | public void onNotificationClicked(Context context, PushedNotification notification) { 22 | Log.d("DemoLogger", "YYNotificationReceiver onNotificationClicked " + notification.id + " values " + notification.payload); 23 | Toast.makeText(context, "YYNotificationReceiver clicked payload: " + notification.payload, Toast.LENGTH_SHORT).show(); 24 | Intent intent = new Intent(context, DrawActivity.class); 25 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 26 | context.startActivity(intent); 27 | } 28 | 29 | @Override 30 | public void onNotificationArrived(Context context, PushedNotification notification) { 31 | Log.d("DemoLogger", "YYNotificationReceiver onNotificationArrived " + notification.id + " values " + notification.payload); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/entity/Message.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo.entity; 2 | 3 | public class Message { 4 | 5 | private String message; 6 | private String nickName; 7 | private String type = "chat_message"; 8 | 9 | public String getMessage() { 10 | return message; 11 | } 12 | 13 | public String getNickName() { 14 | return nickName; 15 | } 16 | 17 | public void setMessage(String message) { 18 | this.message = message; 19 | } 20 | 21 | public void setNickName(String nickName) { 22 | this.nickName = nickName; 23 | } 24 | 25 | public String getType() { 26 | return type; 27 | } 28 | 29 | public void setType(String type) { 30 | this.type = type; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/test/TestActivity.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo.test; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | import android.widget.TextView; 8 | 9 | import com.yy.httpproxy.Config; 10 | import com.yy.httpproxy.ProxyClient; 11 | import com.yy.httpproxy.service.DefaultDnsHandler; 12 | import com.yy.httpproxy.service.DefaultNotificationHandler; 13 | import com.yy.httpproxy.subscribe.ConnectCallback; 14 | import com.yy.httpproxy.subscribe.PushCallback; 15 | import com.yy.misaka.demo.R; 16 | import java.util.Set; 17 | 18 | /** 19 | * Created by Administrator on 2016/7/19. 20 | */ 21 | public class TestActivity extends Activity implements ConnectCallback, PushCallback{ 22 | 23 | private static final String TAG = "TestActivity"; 24 | public static String host = "https://spush.yy.com"; 25 | public static final String topic = "testTopic"; 26 | public ProxyClient proxyClient; 27 | private TextView tv_socketState,tv_pushId; 28 | public String pushId; 29 | 30 | private TestConnectCallBack connectCallBack; 31 | private TestPushCallBack pushCallBack; 32 | 33 | public void setPushCallBack(TestPushCallBack pushCallBack) { 34 | this.pushCallBack = pushCallBack; 35 | } 36 | 37 | public void setConnectCallBack(TestConnectCallBack connectCallBack) { 38 | this.connectCallBack = connectCallBack; 39 | } 40 | 41 | @Override 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_test); 45 | initView(); 46 | proxyClient = new ProxyClient(new Config(this).setHost(host) 47 | .setConnectCallback(this) 48 | .setPushCallback(this) 49 | .setDnsHandler(DefaultDnsHandler.class) 50 | .setNotificationHandler(DefaultNotificationHandler.class)); 51 | proxyClient.subscribeBroadcast(topic); 52 | pushId = proxyClient.getPushId(); 53 | tv_pushId.setText("pushId: " + pushId); 54 | proxyClient.subscribeBroadcast(topic); 55 | } 56 | 57 | public void initView() { 58 | tv_socketState = (TextView)findViewById(R.id.tv_state); 59 | tv_pushId = (TextView)findViewById(R.id.tv_pushId); 60 | } 61 | 62 | @Override 63 | public void onConnect(String uid) { 64 | Log.i(TAG, "socket Connect and uid is " + uid); 65 | tv_socketState.setText("connected"); 66 | tv_socketState.setTextColor(Color.GREEN); 67 | if(connectCallBack != null) { 68 | connectCallBack.isConnect(true); 69 | } 70 | } 71 | 72 | @Override 73 | public void onDisconnect() { 74 | Log.i(TAG, "socket disConnect"); 75 | tv_socketState.setText("disconnected"); 76 | tv_socketState.setTextColor(Color.RED); 77 | if(connectCallBack != null) { 78 | connectCallBack.isConnect(false); 79 | } 80 | } 81 | 82 | @Override 83 | public void onPush(String data) { 84 | Log.i(TAG, data); 85 | pushCallBack.onPush(data); 86 | } 87 | 88 | 89 | public interface TestConnectCallBack { 90 | void isConnect(boolean state); 91 | } 92 | 93 | public interface TestPushCallBack { 94 | void onPush(String data); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/util/HttpUtils.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo.util; 2 | 3 | 4 | import java.security.cert.CertificateException; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import javax.net.ssl.HostnameVerifier; 9 | import javax.net.ssl.SSLContext; 10 | import javax.net.ssl.SSLSession; 11 | import javax.net.ssl.SSLSocketFactory; 12 | import javax.net.ssl.TrustManager; 13 | import javax.net.ssl.X509TrustManager; 14 | 15 | import okhttp3.Callback; 16 | import okhttp3.OkHttpClient; 17 | import okhttp3.Protocol; 18 | import okhttp3.Request; 19 | import okhttp3.internal.Util; 20 | 21 | /** 22 | * Created by Administrator on 2016/4/27. 23 | */ 24 | public class HttpUtils { 25 | 26 | private static OkHttpClient okHttpClient = getUnsafeOkHttpClient(); 27 | 28 | public static void request(String url, HashMap params, Callback callback) { 29 | StringBuilder okRequestURL = new StringBuilder(url); 30 | if (params != null) { 31 | okRequestURL.append("?"); 32 | for (String key : params.keySet()) { 33 | if (params.get(key) instanceof String) { 34 | okRequestURL.append(key).append("=").append(params.get(key).toString()).append("&"); 35 | } else { 36 | String encodeStr = JsonHelper.toJson(params.get(key), "UTF-8"); 37 | okRequestURL.append(key).append("=").append(encodeStr).append("&"); 38 | } 39 | } 40 | } 41 | Request request = new Request.Builder().url(okRequestURL.toString()).build(); 42 | okHttpClient.newCall(request).enqueue(callback); 43 | } 44 | 45 | private static OkHttpClient getUnsafeOkHttpClient() { 46 | try { 47 | // Create a trust manager that does not validate certificate chains 48 | X509TrustManager manager = new X509TrustManager() { 49 | @Override 50 | public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { 51 | } 52 | 53 | @Override 54 | public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { 55 | } 56 | 57 | @Override 58 | public java.security.cert.X509Certificate[] getAcceptedIssuers() { 59 | return new java.security.cert.X509Certificate[]{}; 60 | } 61 | }; 62 | final TrustManager[] trustAllCerts = new TrustManager[]{ 63 | manager 64 | }; 65 | 66 | // Install the all-trusting trust manager 67 | final SSLContext sslContext = SSLContext.getInstance("SSL"); 68 | sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); 69 | // Create an ssl socket factory with our all-trusting manager 70 | final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); 71 | 72 | OkHttpClient.Builder builder = new OkHttpClient.Builder(); 73 | builder.sslSocketFactory(sslSocketFactory, manager); 74 | builder.hostnameVerifier(new HostnameVerifier() { 75 | @Override 76 | public boolean verify(String hostname, SSLSession session) { 77 | return true; 78 | } 79 | }); 80 | // builder.protocols(Util.immutableList( 81 | // Protocol.HTTP_1_1)); 82 | OkHttpClient okHttpClient = builder.build(); 83 | return okHttpClient; 84 | } catch (Exception e) { 85 | throw new RuntimeException(e); 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /android-demo/src/main/java/com/yy/misaka/demo/util/JsonHelper.java: -------------------------------------------------------------------------------- 1 | package com.yy.misaka.demo.util; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.google.gson.JsonSyntaxException; 6 | import com.google.gson.reflect.TypeToken; 7 | 8 | import java.io.UnsupportedEncodingException; 9 | import java.lang.reflect.Type; 10 | import java.net.URLEncoder; 11 | import java.util.List; 12 | 13 | public class JsonHelper { 14 | 15 | private static Gson sGson; 16 | 17 | 18 | private static Gson getGson() { 19 | if (sGson == null) { 20 | GsonBuilder gsonBuilder = new GsonBuilder(); 21 | sGson = gsonBuilder.create(); 22 | } 23 | return sGson; 24 | } 25 | 26 | public static T toObject(String jsonString, Class mclass) { 27 | String s = jsonString; 28 | Gson gson = new Gson(); 29 | return gson.fromJson(jsonString, mclass); 30 | } 31 | 32 | public static T jsonToObject(String json, Type tokenType) { 33 | T t = null; 34 | try { 35 | t = getGson().fromJson(json, tokenType); 36 | } catch (JsonSyntaxException e) { 37 | e.printStackTrace(); 38 | } 39 | return t; 40 | } 41 | 42 | public static List toObjectList(String jsonString, Class mclass) { 43 | Gson gson = new Gson(); 44 | return gson.fromJson(jsonString, 45 | new TypeToken>() { 46 | }.getType()); 47 | } 48 | 49 | public static List jsonToObjectList(String json, Type tokenType) { 50 | List t = null; 51 | try { 52 | t = getGson().fromJson(json, 53 | new TypeToken>() { 54 | }.getType()); 55 | } catch (JsonSyntaxException e) { 56 | e.printStackTrace(); 57 | } 58 | return t; 59 | } 60 | 61 | public static String toJson(T object, String encode) { 62 | return getGson().toJson(object); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /android-demo/src/main/res/drawable-xxhdpi/misaka.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuduo/socket.io-push-android/c5738189a79bfae036b8199d0287980c734d9d85/android-demo/src/main/res/drawable-xxhdpi/misaka.jpg -------------------------------------------------------------------------------- /android-demo/src/main/res/layout/activity_chat.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 16 | 17 | 23 | 24 |