一 創建App應用
1.1 在控制檯發(https://mhub.console.aliyun.com)的App列表頁,點擊頁面產品列表中“添加產品”的圖標即可創建一個新的產品(產品是一個集合的概念,產品下包含iOS應用、Android應用)。
然後點擊剛創建的產品,點擊“添加應用”的圖標即可添加Android或者iOS應用(目前只能創建分端應用了,個人感覺還是不分端的好)。
1.2 輸入APP基本信息並在控制檯配置應用
輸入產品的基本信息創建App時需要輸入產品的名稱,上傳產品圖標,選擇產品分類。
其中App的名稱必填,支持中文、英文字母、數字和下劃線,長度限制在4-30位。
1.創建Android應用,並填寫APP名稱和PackageName。
2. 創建iOS應用,並填寫APP名稱和BundleId
二 Android SDK 3.0配置
以下集成是官方Android SDK的快速集成適用於V3.0.0以上版本。通過Maven庫快速集成,該集成方案配置簡單,不容易出問題。 (詳情參考官方集成文檔)
2.1 快速集成(遠程同步)
在Project根目錄下build.gradle文件中配置maven庫URL:
allprojects {
repositories {
jcenter()
maven {
url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
}
}
}
在對應的module下的build.gradle文件中添加對應依賴:
android {
......
defaultConfig {
applicationId "com.xxx.xxx" //包名
......
ndk {
//選擇要添加的對應cpu類型的.so庫。爲了兼容cpu,查看官網SDK的libs多添加幾個
abiFilters 'arm64-v8a', 'armeabi', 'armeabi-v7a', 'mips', 'mips64', 'x86', 'x86_64'
}
......
}
......
}
dependencies {
......
compile 'com.aliyun.ams:alicloud-android-push:3.1.2'
......
}
注 : 如果在添加以上 abiFilter 配置之後android Studio出現以下提示:(一般不會出錯)
NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin.
則在 Project 根目錄的gradle.properties文件中添加:
android.useDeprecatedNdk=true
2.2 AndroidManifest配置
2.2.1 appKey, appSecret配置
在AndroidManifest文件中設置appKey,appSecret:
<application android:name="*****">
<!-- 請填寫你自己的- appKey -->
<meta-data android:name="com.alibaba.app.appkey" android:value="*****"/>
<!-- 請填寫你自己的appSecret -->
<meta-data android:name="com.alibaba.app.appsecret" android:value="****"/>
</application>
(百川的appkey&appSecret不能在阿里雲推送上使用否則應用會找不到對應的appKey)
2.2.2 消息接收Receiver配置
創建消息接收Receiver,繼承自com.alibaba.sdk.android.push.MessageReceiver,並在對應回調中添加業務處理邏輯,可參考以下代碼:
public class MyMessageReceiver extends MessageReceiver {
// 消息接收部分的LOG_TAG
public static final String REC_TAG = "receiver";
@Override
public void onNotification(Context context, String title, String summary, Map<String, String> extraMap) {
// TODO 處理推送通知
Log.e("MyMessageReceiver", "Receive notification, title: " + title + ", summary: " + summary + ", extraMap: " + extraMap);
}
@Override
public void onMessage(Context context, CPushMessage cPushMessage) {
Log.e("MyMessageReceiver", "onMessage, messageId: " + cPushMessage.getMessageId() + ", title: " + cPushMessage.getTitle() + ", content:" + cPushMessage.getContent());
}
@Override
public void onNotificationOpened(Context context, String title, String summary, String extraMap) {
Log.e("MyMessageReceiver", "onNotificationOpened, title: " + title + ", summary: " + summary + ", extraMap:" + extraMap);
}
@Override
protected void onNotificationClickedWithNoAction(Context context, String title, String summary, String extraMap) {
Log.e("MyMessageReceiver", "onNotificationClickedWithNoAction, title: " + title + ", summary: " + summary + ", extraMap:" + extraMap);
}
@Override
protected void onNotificationReceivedInApp(Context context, String title, String summary, Map<String, String> extraMap, int openType, String openActivity, String openUrl) {
Log.e("MyMessageReceiver", "onNotificationReceivedInApp, title: " + title + ", summary: " + summary + ", extraMap:" + extraMap + ", openType:" + openType + ", openActivity:" + openActivity + ", openUrl:" + openUrl);
}
@Override
protected void onNotificationRemoved(Context context, String messageId) {
Log.e("MyMessageReceiver", "onNotificationRemoved");
}
}
將該receiver添加到AndroidManifest.xml中(由於部分手機不允許監聽系統的廣播,把部分過濾器去掉即可。下面示例是已經去掉)
<!-- 消息接收監聽器 (用戶可自主擴展) -->
<receiver
android:name=".MyMessageReceiver"
android:exported="false"> <!-- 爲保證receiver安全,建議設置不可導出,如需對其他應用開放可通過android:permission進行限制 -->
<intent-filter>
<action android:name="com.alibaba.push2.action.NOTIFICATION_OPENED" />
</intent-filter>
<intent-filter>
<action android:name="com.alibaba.push2.action.NOTIFICATION_REMOVED" />
</intent-filter>
<intent-filter>
<action android:name="com.alibaba.sdk.android.push.RECEIVE" />
</intent-filter>
</receiver>
在Manifest中還需要添加以下配置<!-- V3.0.12及以上版本需配置 -->
<service
android:name="com.taobao.accs.internal.AccsJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":channel"/>
<!-- V3.0.7及以上版本需配置 -->
<service android:name="com.alibaba.sdk.android.push.channel.KeepChannelService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":channel" />
<receiver android:name="com.alibaba.sdk.android.push.SystemEventReceiver"
android:process=":channel">
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
</intent-filter>
</receiver>
<!-- V3.0.9及以上版本需配置 -->
<activity
android:name="com.alibaba.sdk.android.push.keeplive.PushExtActivity"
android:configChanges="keyboardHidden|orientation|screenSize|navigation|keyboard"
android:excludeFromRecents="true"
android:exported="false"
android:finishOnTaskLaunch="false"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
android:process=":channel"
>
</activity>
2.2.3 Proguard配置
-keepclasseswithmembernames class ** {
native <methods>;
}
-keepattributes Signature
-keep class sun.misc.Unsafe { *; }
-keep class com.taobao.** {*;}
-keep class com.alibaba.** {*;}
-keep class com.alipay.** {*;}
-keep class com.ut.** {*;}
-keep class com.ta.** {*;}
-keep class anet.**{*;}
-keep class anetwork.**{*;}
-keep class org.android.spdy.**{*;}
-keep class org.android.agoo.**{*;}
-keep class android.os.**{*;}
-dontwarn com.taobao.**
-dontwarn com.alibaba.**
-dontwarn com.alipay.**
-dontwarn anet.**
-dontwarn org.android.spdy.**
-dontwarn org.android.agoo.**
-dontwarn anetwork.**
-dontwarn com.ut.**
-dontwarn com.ta.**
2.2.4 在應用中註冊和啓動推送
以下是應用初始化的官方參考代碼:
import android.app.Application;
import android.content.Context;
import android.util.Log;
import com.alibaba.sdk.android.callback.InitResultCallback;
import com.alibaba.sdk.android.push.CloudPushService;
import com.alibaba.sdk.android.push.CommonCallback;
import com.alibaba.sdk.android.push.noonesdk.PushServiceFactory;
public class MainApplication extends Application {
private static final String TAG = "Init";
@Override
public void onCreate() {
super.onCreate();
initCloudChannel(this);
}
/**
* 初始化雲推送通道
* @param applicationContext
*/
private void initCloudChannel(Context applicationContext) {
PushServiceFactory.init(applicationContext);
CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.register(applicationContext, new CommonCallback() {
@Override
public void onSuccess(String response) {
Log.d(TAG, "init cloudchannel success");
}
@Override
public void onFailed(String errorCode, String errorMessage) {
Log.d(TAG, "init cloudchannel failed -- errorcode:" + errorCode + " -- errorMessage:" + errorMessage);
}
});
}
}
初始化成功後Log輸出在過濾添加正則MPS顯示如下:
三 移動推送輔助通道配置
移動推送的輔助通道的配置主要針對小米和華爲設備(目前只能接收通知,不能直接接收消息)對其他設備也有一定的保活效果。官網有輔助通道相關概念。
3.1 配置應用
註冊你的App, 得到相應的小米AppID,小米AppKey,小米AppSecert。在控制檯註冊你的App, 得到相應的小米AppID,小米AppKey,小米AppSecert。(小米開放平臺)
註冊App,應用審覈通過後,能夠得到華爲的AppID和AppSecert。在控制檯App詳情中設置你的華爲AppID和AppSecert。(注意,您的app不能是草稿狀態,必須是審覈中,或者通過審覈的狀態,不然通道不會生效。請確保您在華爲控制檯激活了推送通道功能)。(華爲開發者聯盟)
注(在每個開發者中心申請,小米的最好聯繫下客服會快點,小米創建應用很快,就是開發者審覈慢點;華爲的開發這審覈快,創建應用填寫基本信息也是要點時間的。)
如果你的應用是國際版的可以在FCM平臺上添加項目,以提高推送的到達率,接入前提手機必須安裝google play services, 否則註冊不成功, 大部分國內的手機是谷歌服務被剝離了:(FCM平臺需要翻牆,如果不需要國際化,則不必配置)
在以上平臺申請成功後會看到:上面是小米的,下面是華爲的。
然後就可以在阿里雲控制檯的應用列表填寫擴展信息了
3.2 下載擴展包
將小米華爲擴展包拷貝到你項目的Lib目錄下,下載地址。
如果碰到arr文件擴展包無法添加的情況,建議解壓aar將其中的jar引入,manifest中的配置複製到你當前項目即可。
將華爲小米擴展包放置到app module的libs路徑下,並在app module的build.gradle文件中添加如下配置:
repositories {
flatDir {
dirs 'libs' //this way we can find the .aar file in libs folder
}
}
...
dependencies {
......
compile(name: 'third-push-support-3.0.5', ext: 'aar')
}
如需配置GCM/FCM通道還需要添加Firebase SDK依賴:
dependencies {
......
compile ('com.google.firebase:firebase-messaging:9.6.1')
}
3.3 Proguard配置
集成推送SDK的工程開啓代碼混淆,在Proguard配置的基礎上,需要添加以下輔助通道的Proguard配置。
# 小米通道
-keep class com.xiaomi.** {*;}
-dontwarn com.xiaomi.**
# 華爲通道
-keep class com.huawei.** {*;}
-dontwarn com.huawei.**
# GCM/FCM通道
-keep class com.google.firebase.**{*;}
- dontwarn com.google.firebase.**
3.4 在應用中初始化小米華爲初始化通道
將以下代碼加入你application.onCreate()方法中初始通道。注意:輔助通道註冊需要放在推送SDK初始化代碼之後。
// 註冊方法會自動判斷是否支持小米系統推送,如不支持會跳過註冊。
MiPushRegister.register(applicationContext, "小米AppID", "小米AppKey");
// 註冊方法會自動判斷是否支持華爲系統推送,如不支持會跳過註冊。
HuaWeiRegister.register(applicationContext);
//GCM/FCM輔助通道註冊
GcmRegister.register(this, sendId, applicationId); //sendId/applicationId爲步驟獲得的參數
註冊方法會自動判斷是否支持小米/華爲系統推送,如不支持會跳過註冊。
3.5 在日誌中查看初始化情況
華爲通道初始化成功,可以看到以下日誌:
11-11 22:21:33.671 30248-30324/com.xxx E/MPS:HuaWeiRegister: HuaWeiRegister checkDevice flag=true //確認是華爲的手機
11-11 22:21:33.674 30248-30324/com.xxx E/MPS:HuaWeiRegister﹕ Register huawei push............ //開始註冊華爲手機
11-11 22:21:33.714 29643-30328/com.xxx E/MPS:HuaWeiRegister﹕ huawei register success,token = 08657430243125472000000411000001
11-11 22:21:33.714 29643-30328/com.xxx E/MPS:HuaWeiRegister﹕ report huaweiPushId intent... //完成華爲註冊和信息上報
小米通道初始化成功,可以看到以下日誌:
12-09 22:20:39.710 19566-19566/com.xxx E/MPS:MiPushRegister: MiPushRegister checkDevice flag=true //確認是小米的手機
12-09 22:20:39.712 19566-19566/com.xxx E/MPS:MiPushRegister: Register mipush. //開始註冊小米
12-09 22:20:40.596 19566-19733/com.xxx E/MPS:MiPushRegister: XiaoMi register success. //小米註冊成功 regid=d//igwEhgBGCI2TG6lWqlCesc0I6xE1wUhNCBXQ8uNOi/dDZioYXVysbrVrvRmyEVPn9nWz92D28IzYbA1RzoGDyTzYZwXKfBHEQkrey4G8=
GCM/FCM通道初始化成功,可以看到以下日誌:
05-19 19:18:44.530 19153-19177/com.xxx D/MPS:GcmRegister: token from register: eWIXLYCNP0Q:APA91bFUAgxj6XYf5okyoCBnRPw1UwITndzXrvPDgbdI2N44PYm17hFEBiNXNQJrJ8bOG_xjw3c3UPDAhzNMTLNjlAKcjUanKyLA6E3k4wEmgZuhgUT02UMmMvH2LVA1L2Z4-l-cT_Ug
初始化成功後,由於小米/華爲系統管控比較嚴格,所以應用被殺死後仍不能接收通知,需要配置配置專門的輔助彈窗。
3.6 系統輔助彈窗配置
輔助官網已經廢除了MiPushSystemNotificationActivity(不過不影響使用),建議使用繼承
指定打開的託管的彈窗Activity在AndroidManifest.xml中註冊需要聲明android:exported=true,還有如果在PopupActivity的AndroidPopupActivity
onSysNoticeOpened
方法中沒有指定跳轉界面,或者在onCreate中沒有設置佈局文件,點擊輔助彈窗通知後只會顯示一個空白界面。
import com.alibaba.sdk.android.push.AndroidPopupActivity;
public class PopupPushActivity extends AndroidPopupActivity{
static final String TAG = "PopupPushActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(activity_popuppush);
}
/**
* 實現通知打開回調方法,獲取通知相關信息
* @param title 標題
* @param summary 內容
* @param extMap 額外參數
*/
@Override
protected void onSysNoticeOpened(String title, String summary, Map<String, String> extMap) {
Log.d("onSysNoticeOpened, title: " + title + ", content: " + summary + ", extMap: " + extMap);
}
}
推送通知打開指定Activity時如何操作
推送通知打開指定Activity時如何獲取推送通知參數
四 Android SDK服務器配置 (當前推送對象是Android,iOS的證書配置完好的話選擇全推也是可以的)
官網服務器移動推送Demo需要添加推送的SDK依賴(本示例代碼是Java版本,如需要其他版本參看官網其他示例)
- SDK 地址
- Demo 地址
首先下載推送的push-openapi-java-demo,由於官網是使用IDEA開發的Demo,所以如果你使用Eclipse或者MyEclipse要以Maven的方式導入項目。
4.1 獲取AccessKeyId和AccessKeySecret
前往阿里雲官網控制檯獲取
4.2 獲取appKey
>>前往移動推動控制檯獲取 app列表->應用證書
在開發工具中打開push-openapi-java-demo中的src/test/resources/push.properties.template文件修改配置文件名稱爲push.properties
以下是該配置文件說明:
4.3 引入SDK依賴
在下載的SDK中找到aliyun-java-sdk-push,
如果使用IDEA開發的分別將aliyun-java-sdk-push,aliyun-java-sdk-core和push-openapi-java-demo並且給push-openapi-java-demo添加aliyun-java-sdk-push,aliyun-java-sdk-core依賴。
如果使用Eclipse(或者MyEclipse)開發,以maven項目導入aliyun-java-sdk-push,aliyun-java-sdk-core和push-openapi-java-demo然後再給push-openapi-java-demo添加aliyun-java-sdk-push,aliyun-java-sdk-core依賴。
官網上是直接使用maven添加的(但有的時候可能同步依賴不完整)
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-push</artifactId>
<version>3.0.2</version>
</dependency>
添加依賴成功後IDEA的文件目錄如下:
添加依賴成功後MyEclipse的文件目錄如下:
親測都能夠實現推送測試。
五 服務端測試給Android發送通知
如果想自己拼接url進行推送,不使用Demo可以參考以下示例代碼:將對應的access_key_id,access_key_secret,appkey換成自己在控制檯申請的即可執行main方法。
import sun.misc.BASE64Encoder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.SignatureException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* 移動推送OpenAPI調用示例
* 以PushNoticeToAndroid接口爲例,其他接口請替換相應接口名稱及私有參數
*/
public class Main {
//賬號AK信息請填寫(必選)
private static String access_key_id = "";
//賬號AK信息請填寫(必選)
private static String access_key_secret = "";
//賬號AppKey信息請填寫(必選)
private static String appkey = "";
//以下參數不需要修改
//STS臨時授權方式訪問時該參數爲必選,使用主賬號AK和RAM子賬號AK不需要填寫
private static String security_token = "";
private final static String VOD_DOMAIN = "http://cloudpush.aliyuncs.com";
private final static String ISO8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private final static String HTTP_METHOD_GET = "GET";
private final static String HMAC_SHA1_ALGORITHM = "HmacSHA1";
private final static String UTF_8 = "utf-8";
private final static Logger LOG = Logger.getLogger(Main.class.getName());
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//生成私有參數,不同API需要修改
Map<String, String> privateParams = generatePrivateParamters();
//生成公共參數,不需要修改
Map<String, String> publicParams = generatePublicParamters();
//生成OpenAPI地址,不需要修改
String URL = generateOpenAPIURL(publicParams, privateParams);
//發送HTTP GET 請求
httpGet(URL);
}
/**
* 移動推送OpenAPI私有參數
* 不同API需要修改此方法中的參數
* 推送高級接口 https://help.aliyun.com/knowledge_detail/48089.html
*
* @return
*/
private static Map<String, String> generatePrivateParamters() {
// 接口私有參數列表, 不同API請替換相應參數
Map<String, String> privateParams = new HashMap<String, String>();
// API名稱
privateParams.put("Action", "Push");
// AppKey
privateParams.put("AppKey", appkey);
//推送目標: DEVICE:按設備推送 ALIAS : 按別名推送 ACCOUNT:按帳號推送 TAG:按標籤推送; ALL: 廣播推送
privateParams.put("Target", "ALL");
//根據Target來設定
privateParams.put("TargetValue", "ALL");
// 消息類型 MESSAGE NOTICE
privateParams.put("PushType", "NOTICE");
// 設備類型 ANDROID iOS ALL
privateParams.put("DeviceType", "ANDROID");
// 推送的標題
privateParams.put("Title", "title");
// 推送的內容
privateParams.put("Body", "body");
//通知的提醒方式 "VIBRATE" : 震動 "SOUND" : 聲音 "BOTH" : 聲音和震動 NONE : 靜音
privateParams.put("AndroidNotifyType", "BOTH");
privateParams.put("AndroidNotificationBarType", "1");
privateParams.put("AndroidNotificationBarPriority", "1");
privateParams.put("AndroidOpenType", "URL");
privateParams.put("AndroidOpenUrl", "http://www.aliyun.com");
privateParams.put("AndroidMusic", "default");
privateParams.put("AndroidPopupActivity", "com.alibaba.cloudpushdemo.bizactivity.ThirdPushPopupActivity");
privateParams.put("AndroidPopupTitle", "PopupTitle");
privateParams.put("AndroidPopupBody", "PopupBody");
privateParams.put("PushTime", generateTimestamp(System.currentTimeMillis()));
privateParams.put("ExpireTime", generateTimestamp(System.currentTimeMillis() + 12 * 3600 * 1000));
// 離線消息是否保存,若保存, 在推送時候,用戶即使不在線,下一次上線則會收到
privateParams.put("StoreOffline", "true");
//設定通知的擴展屬性
privateParams.put("ExtParameters", "{'key1':'value1','api_name':'PushRequest'}");
return privateParams;
}
/**
* 移動推送OpenAPI公共參數
* 不需要修改
*
* @return
*/
private static Map<String, String> generatePublicParamters() {
Map<String, String> publicParams = new HashMap<String, String>();
publicParams.put("Format", "JSON");
publicParams.put("Version", "2016-08-01");
publicParams.put("AccessKeyId", access_key_id);
publicParams.put("SignatureMethod", "HMAC-SHA1");
publicParams.put("Timestamp", generateTimestamp(System.currentTimeMillis()));
publicParams.put("SignatureVersion", "1.0");
publicParams.put("SignatureNonce", generateRandom());
if (security_token != null && security_token.length() > 0) {
publicParams.put("SecurityToken", security_token);
}
return publicParams;
}
/**
* 生成OpenAPI地址
*
* @param privateParams
* @return
* @throws Exception
*/
private static String generateOpenAPIURL(Map<String, String> publicParams, Map<String, String> privateParams) {
return generateURL(VOD_DOMAIN, HTTP_METHOD_GET, publicParams, privateParams);
}
/**
* @param domain 請求地址
* @param httpMethod HTTP請求方式GET,POST等
* @param publicParams 公共參數
* @param privateParams 接口的私有參數
* @return 最後的url
*/
private static String generateURL(String domain, String httpMethod, Map<String, String> publicParams, Map<String, String> privateParams) {
List<String> allEncodeParams = getAllParams(publicParams, privateParams);
String cqsString = getCQS(allEncodeParams);
out("CanonicalizedQueryString = " + cqsString);
String stringToSign = httpMethod + "&" + percentEncode("/") + "&" + percentEncode(cqsString);
out("StringtoSign = " + stringToSign);
String signature = hmacSHA1Signature(access_key_secret, stringToSign);
out("Signature = " + signature);
return domain + "?" + cqsString + "&" + percentEncode("Signature") + "=" + percentEncode(signature);
}
private static List<String> getAllParams(Map<String, String> publicParams, Map<String, String> privateParams) {
List<String> encodeParams = new ArrayList<String>();
List<String> publicParamsList = paramsUrlEncode(publicParams);
List<String> privateParamsList = paramsUrlEncode(privateParams);
encodeParams.addAll(publicParamsList);
encodeParams.addAll(privateParamsList);
return encodeParams;
}
/**
* 將參數和值都urlEncode一下
*/
private static List<String> paramsUrlEncode(Map<String, String> params) {
List<String> encodeParams = new ArrayList<String>();
if (params != null) {
for (String key : params.keySet()) {
String value = params.get(key);
//將參數和值都urlEncode一下。
String encodeKey = percentEncode(key);
String encodeVal = percentEncode(value);
encodeParams.add(encodeKey + "=" + encodeVal);
}
}
return encodeParams;
}
/**
* 參數urlEncode
*
* @param value
* @return
*/
private static String percentEncode(String value) {
try {
String urlEncodeOrignStr = URLEncoder.encode(value, "UTF-8");
String plusReplaced = urlEncodeOrignStr.replace("+", "%20");
String starReplaced = plusReplaced.replace("*", "%2A");
String waveReplaced = starReplaced.replace("%7E", "~");
return waveReplaced;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return value;
}
/**
* 獲取CQS 的字符串
*
* @param allParams
* @return
*/
private static String getCQS(List<String> allParams) {
ParamsComparator paramsComparator = new ParamsComparator();
Collections.sort(allParams, paramsComparator);
String cqString = "";
for (int i = 0; i < allParams.size(); i++) {
cqString += allParams.get(i);
if (i != allParams.size() - 1) {
cqString += "&";
}
}
return cqString;
}
private static class ParamsComparator implements Comparator<String> {
@Override
public int compare(String lhs, String rhs) {
return lhs.compareTo(rhs);
}
}
private static String hmacSHA1Signature(String accessKeySecret, String stringtoSign) {
try {
String key = accessKeySecret + "&";
try {
SecretKeySpec signKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signKey);
byte[] rawHmac = mac.doFinal(stringtoSign.getBytes());
//按照Base64 編碼規則把上面的 HMAC 值編碼成字符串,即得到簽名值(Signature)
return new String(new BASE64Encoder().encode(rawHmac));
} catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
} catch (SignatureException e) {
e.printStackTrace();
}
return "";
}
/**
* 生成隨機數
*
* @return
*/
private static String generateRandom() {
String signatureNonce = UUID.randomUUID().toString();
return signatureNonce;
}
/**
* 生成當前UTC時間戳
*
* @return
*/
public static String generateTimestamp(long time) {
Date date = new Date(time);
SimpleDateFormat df = new SimpleDateFormat(ISO8601_DATE_FORMAT);
df.setTimeZone(new SimpleTimeZone(0, "GMT"));
return df.format(date);
}
private static String httpGet(String url) throws IOException {
/*
* Read and covert a inputStream to a String.
* Referred this:
* http://stackoverflow.com/questions/309424/read-convert-an-inputstream-to-a-string
*/
out("URL = " + url);
@SuppressWarnings("resource")
Scanner s = new Scanner(new URL(url).openStream(), UTF_8).useDelimiter("\\A");
try {
String resposne = s.hasNext() ? s.next() : "true";
out("Response = " + resposne);
return resposne;
} finally {
s.close();
}
}
private static void out(String newLine) {
LOG.log(Level.INFO, newLine);
}
}