Android 整合華為推送 push
由於專案需要我們不得不對華為push進行研究。
按照國際慣例先百度一波,發現各個大牛都是對於華為push的填坑,很明顯,這個推送的問題還是有很多的。
這裡引用:Android整合華為推送踩坑問題總結
- 使用老版push還是新版push
- PushReceiver中的onEvent()回撥觸發問題
- APP接收到推送後,點選訊息,總是會先開啟啟動頁
- 如何自定義動作intent
如何解決請跳轉連結檢視詳細內容。
關於華為推送的注意點:
支援NC功能的手機:部分EMUI4.0和4.1的手機,以及EMUI5.0及之後的華為手機。
是否接受通知欄訊息:當是中國大陸地區的華為手機,必須滿足EMUI版本不低於EMUI5.1
當是海外地區的華為手機或者非華為品牌手機,則必須滿足華為移動服務的版本不低於2.5.0
針對以上:
//判斷EMUI 大於 等於 12 相當於5.1 int emuiApiLevel = 0; try { Class cls = Class.forName("android.os.SystemProperties"); Method method = cls.getDeclaredMethod("get", new Class[]{String.class}); emuiApiLevel = Integer.parseInt((String) method.invoke(cls, new Object[]{"ro.build.hw_emui_api_level"})); } catch (Exception e) { e.printStackTrace(); } //判斷服務版本 大於等於 250 PackageInfo pi = null; PackageManager pm = context.getPackageManager(); int hwid = 0; try { pi = pm.getPackageInfo("com.huawei.hwid", 0); if (pi != null) { result = pi.versionCode; } } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); }
一、註冊華為開發者聯盟賬號 右上角進入管理中心
申請push服務 建立應用。
注意:
SHA256證書指紋1 此證書需要打包你的apk (放在根目錄 方便)然後在Terminal 中輸入
keytool -v -list -keystore 名稱.jks
輸入密碼後 即可檢視
二、為了每次不用我們打包後安裝
File -> project Structure -> app -> Signing 新增我們建立的jks
-> Build Types -> debug ->Signing Config 選擇剛才建立的jks 就好。
有時候我們會忽略這一點 以至於 每次都會 6003 告訴我們 簽名有問題
大家注意一下就好。
三、開發整合
HMS Agent套件 HMSAgent_2.6.1.302.zip
解壓後點擊 GetHMSAgent_cn.bat
按照提示 輸入相關內容 沒有 直接Enter 就好
然後找到copysrc資料夾 將java 資料夾中的所有內容 拷貝到你的專案裡
目錄請看下圖 com下 dak 是我專案的包名
然後放入 華為的Agent 套件
注意: 目錄一定要相對應
然後把AppManifestConfig.xml 中內容 放入到AndroidManifest.xml 中。
有一個標紅點 需要放入一個Receiver
我們把華為官方的simple中 HuaweiPushRevicer 拿過來就好了。
public class HuaweiPushRevicer extends PushReceiver {
public static final String TAG = "HuaweiPushRevicer";
public static final String ACTION_UPDATEUI = "action.updateUI";
public static final String ACTION_TOKEN = "action.updateToken";
private static List<IPushCallback> pushCallbacks = new ArrayList<IPushCallback>();
private static final Object CALLBACK_LOCK = new Object();
public interface IPushCallback {
void onReceive(Intent intent);
}
public static void registerPushCallback(IPushCallback callback) {
synchronized (CALLBACK_LOCK) {
pushCallbacks.add(callback);
}
}
public static void unRegisterPushCallback(IPushCallback callback) {
synchronized (CALLBACK_LOCK) {
pushCallbacks.remove(callback);
}
}
@Override
public void onToken(Context context, String tokenIn, Bundle extras) {
Log.e("onToken:", tokenIn);
String belongId = extras.getString("belongId");
Intent intent = new Intent();
intent.setAction(ACTION_TOKEN);
intent.putExtra(ACTION_TOKEN, tokenIn);
callBack(intent);
intent = new Intent();
intent.setAction(ACTION_UPDATEUI);
intent.putExtra("log", "belongId is:" + belongId + " Token is:" + tokenIn);
callBack(intent);
}
@Override
public boolean onPushMsg(Context context, byte[] msg, Bundle bundle) {
Log.e("onPushMsg:", "接收訊息");
try {
//CP可以自己解析訊息內容,然後做相應的處理 | CP can parse message content on its own, and then do the appropriate processing
String content = new String(msg, "UTF-8");
Intent intent = new Intent();
intent.setAction(ACTION_UPDATEUI);
intent.putExtra("log", "Receive a push pass message with the message:" + content);
callBack(intent);
} catch (Exception e) {
Intent intent = new Intent();
intent.setAction(ACTION_UPDATEUI);
intent.putExtra("log", "Receive push pass message, exception:" + e.getMessage());
callBack(intent);
}
return false;
}
public void onEvent(Context context, Event event, Bundle extras) {
Log.e("onEvent:", "事件");
Intent intent = new Intent();
intent.setAction(ACTION_UPDATEUI);
int notifyId = 0;
if (Event.NOTIFICATION_OPENED.equals(event) || Event.NOTIFICATION_CLICK_BTN.equals(event)) {
notifyId = extras.getInt(BOUND_KEY.pushNotifyId, 0);
if (0 != notifyId) {
NotificationManager manager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(notifyId);
}
}
String message = extras.getString(BOUND_KEY.pushMsgKey);
intent.putExtra("log", "Received event,notifyId:" + notifyId + " msg:" + message);
callBack(intent);
super.onEvent(context, event, extras);
}
@Override
public void onPushState(Context context, boolean pushState) {
Log.e("onPushState:", "接收狀態");
Intent intent = new Intent();
intent.setAction(ACTION_UPDATEUI);
intent.putExtra("log", "The Push connection status is:" + pushState);
callBack(intent);
}
private static void callBack(Intent intent) {
synchronized (CALLBACK_LOCK) {
for (IPushCallback callback : pushCallbacks) {
if (callback != null) {
callback.onReceive(intent);
}
}
}
}
}
注意不要混亂。
在project build.gradle 中新增 maven {url 'http://developer.huawei.com/repo/'}
在module build.gradle 中新增 如下
// 此處版本號僅為示例,請手動修改成實際整合的HMSSDK版本號
String HMSSDKVer ='2.6.1.301'
compile 'com.huawei.android.hms:iap:'+HMSSDKVer
compile 'com.huawei.android.hms:game:'+HMSSDKVer
compile 'com.huawei.android.hms:sns:'+HMSSDKVer
compile 'com.huawei.android.hms:hwid:'+HMSSDKVer
compile 'com.huawei.android.hms:push:'+HMSSDKVer
compile 'com.huawei.android.hms:opendevice:'+HMSSDKVer
需要哪個新增哪個就好。 Sync Now 一下
檢視Agent 套件 是否還繼續報錯。
如果報錯 看下是否少添加了內容
值得一提:
resConfigs "en", "zh-rCN","其他應用需要支援的語言"
確認專案需求是否需要 。
四、程式碼內容
在Application 的 onCreate 中 初始化套件
HMSAgent.init(this);
在第一個Activity 中連線 我在Main中
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity:";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connectHMSAgent();
Button button = findViewById(R.id.btn_push);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this,PushActivity.class));
}
});
}
private void connectHMSAgent() {
HMSAgent.connect(this, new ConnectHandler() {
@Override
public void onConnect(int rst) {
Log.e("MainActivity:","HMS connect end:" + rst);
}
});
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.dak.administrator.hwpushsimple.MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="跳轉push"
android:id="@+id/btn_push"
/>
</LinearLayout>
以下是 官方simple 中測試 Activity 我只拿了 push 部份 可以用來測試
public class PushActivity extends AppCompatActivity implements HuaweiPushRevicer.IPushCallback, View.OnClickListener {
private String token;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_push);
Button btn = (Button) findViewById(R.id.btn_push);
if (btn != null) {
btn.setTextColor(Color.RED);
btn.setEnabled(false);
}
findViewById(R.id.btn_gettoken).setOnClickListener(this);
findViewById(R.id.btn_deletetoken).setOnClickListener(this);
findViewById(R.id.btn_getpushstatus).setOnClickListener(this);
findViewById(R.id.btn_setnormal).setOnClickListener(this);
findViewById(R.id.btn_setnofify).setOnClickListener(this);
findViewById(R.id.btn_agreement).setOnClickListener(this);
registerBroadcast();
}
/**
* 獲取token | get push token
*/
private void getToken() {
showLog("get token: begin");
HMSAgent.Push.getToken(new GetTokenHandler() {
@Override
public void onResult(int rtnCode) {
showLog("get token: end code=" + rtnCode);
}
});
}
/**
* 刪除token | delete push token
*/
private void deleteToken(){
showLog("deleteToken:begin");
HMSAgent.Push.deleteToken(token, new DeleteTokenHandler() {
@Override
public void onResult(int rst) {
showLog("deleteToken:end code=" + rst);
}
});
}
/**
* 獲取push狀態 | Get Push State
*/
private void getPushStatus() {
showLog("getPushState:begin");
HMSAgent.Push.getPushState(new GetPushStateHandler() {
@Override
public void onResult(int rst) {
showLog("getPushState:end code=" + rst);
}
});
}
/**
* 設定是否接收普通透傳訊息 | Set whether to receive normal pass messages
* @param enable 是否開啟 | enabled or not
*/
private void setReceiveNormalMsg(boolean enable){
showLog("enableReceiveNormalMsg:begin");
HMSAgent.Push.enableReceiveNormalMsg(enable, new EnableReceiveNormalMsgHandler() {
@Override
public void onResult(int rst) {
showLog("enableReceiveNormalMsg:end code=" + rst);
}
});
}
/**
* 設定接收通知訊息 | Set up receive notification messages
* 注意:當是中國大陸地區的華為手機,必須滿足EMUI版本不低於EMUI5.1
* 當是海外地區的華為手機或者非華為品牌手機,則必須滿足華為移動服務的版本不低於2.5.0。
* @param enable 是否開啟 | enabled or not
*/
private void setReceiveNotifyMsg(boolean enable){
showLog("enableReceiveNotifyMsg:begin");
HMSAgent.Push.enableReceiveNotifyMsg(enable, new EnableReceiveNotifyMsgHandler() {
@Override
public void onResult(int rst) {
showLog("enableReceiveNotifyMsg:end code=" + rst);
}
});
}
/**
* 顯示push協議 | Show Push protocol
*/
private void showAgreement(){
showLog("queryAgreement:begin");
HMSAgent.Push.queryAgreement(new QueryAgreementHandler() {
@Override
public void onResult(int rst) {
showLog("queryAgreement:end code=" + rst);
}
});
}
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.btn_push) {
// 本頁面切換到本頁面的按鈕事件不處理 | "This page switches to itself" button event does not need to be handled
return;
} else {
// 如果不是tab切換按鈕則處理業務按鈕事件 | Handle Business button events without the TAB toggle button
switch (id) {
case R.id.btn_gettoken:
getToken();
break;
case R.id.btn_deletetoken:
deleteToken();
break;
case R.id.btn_getpushstatus:
getPushStatus();
break;
case R.id.btn_setnormal:
setReceiveNormalMsg(true);
break;
case R.id.btn_setnofify:
setReceiveNotifyMsg(true);
break;
case R.id.btn_agreement:
showAgreement();
break;
default:
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
HuaweiPushRevicer.unRegisterPushCallback(this);;
}
/**
* 以下程式碼為sample自身邏輯,和業務能力不相關
* 作用僅僅為了在sample介面上顯示push相關資訊
*/
private void registerBroadcast() {
HuaweiPushRevicer.registerPushCallback(this);
}
@Override
public void onReceive(Intent intent) {
if (intent != null) {
String action = intent.getAction();
Bundle b = intent.getExtras();
if (b != null && ACTION_TOKEN.equals(action)) {
token = b.getString(ACTION_TOKEN);
} else if (b != null && ACTION_UPDATEUI.equals(action)) {
String log = b.getString("log");
showLog(log);
}
}
}
StringBuffer sbLog = new StringBuffer();
protected void showLog(String logLine) {
DateFormat format = new java.text.SimpleDateFormat("MMddhhmmssSSS");
String time = format.format(new Date());
sbLog.append(time+":"+logLine);
sbLog.append('\n');
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
View vText = findViewById(R.id.tv_log);
if (vText != null && vText instanceof TextView) {
TextView tvLog = (TextView)vText;
tvLog.setText(sbLog.toString());
}
View vScrool = findViewById(R.id.sv_log);
if (vScrool != null && vScrool instanceof ScrollView) {
ScrollView svLog = (ScrollView)vScrool;
svLog.fullScroll(View.FOCUS_DOWN);
}
}
});
}
//如何判斷EMUI版本>=4.1
private boolean isSwitchEnable(){
int emuiApiLevel = 0;
try {
Class cls = Class.forName("android.os.SystemProperties");
Method method = cls.getDeclaredMethod("get", new Class[]{String.class});
emuiApiLevel = Integer.parseInt((String) method.invoke(cls, new Object[]{"ro.build.hw_emui_api_level"}));
} catch (Exception e) {
e.printStackTrace();
}
return emuiApiLevel > 5.0;
}
}
push.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF">
<include
android:id="@+id/layout_commom"
layout="@layout/layout_head"/>
<LinearLayout
android:id="@+id/layout_first"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/layout_commom"
android:orientation="horizontal">
<Button
android:id="@+id/btn_gettoken"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="獲取token"/>
<Button
android:id="@+id/btn_deletetoken"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="刪除token"/>
</LinearLayout>
<LinearLayout
android:id="@+id/layout_second"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/layout_first"
android:orientation="horizontal">
<Button
android:id="@+id/btn_setnormal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="切換普通訊息開關"/>
<Button
android:id="@+id/btn_setnofify"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="切換通知訊息開關"/>
</LinearLayout>
<LinearLayout
android:id="@+id/layout_third"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/layout_second"
android:orientation="horizontal">
<Button
android:id="@+id/btn_agreement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="協議"/>
<Button
android:id="@+id/btn_getpushstatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="獲取push狀態"/>
</LinearLayout>
<ScrollView
android:id="@+id/sv_log"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/layout_third">
<TextView
android:id="@+id/tv_log"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textColor="#000000"
android:paddingBottom="30dip"
android:text="日誌顯示區:" />
</ScrollView>
</RelativeLayout>
head.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#FFFFFF"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_game"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/button_color"
android:minWidth="60dp"
android:text="遊戲"/>
<Button
android:id="@+id/btn_iap"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/button_color"
android:minWidth="60dp"
android:text="支付"/>
<Button
android:id="@+id/btn_id"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/button_color"
android:minWidth="60dp"
android:text="帳號"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_sns"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/button_color"
android:minWidth="60dp"
android:text="社交"/>
<Button
android:id="@+id/btn_push"
android:includeFontPadding="false"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/button_color"
android:minWidth="60dp"
android:text="push"/>
<Button
android:id="@+id/btn_opendevice"
android:includeFontPadding="false"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/button_color"
android:minWidth="60dp"
android:text="開放裝置id"/>
</LinearLayout>
</LinearLayout>
ok 大功告成。
由於我在獲取token的時候沒有返回值。
提單後告知 我小米手機 下載的最新華為移動服務 不支援。 也就沒測試了。 很難受。
不過 以上方法 經過我多方驗證,把或許會犯錯的點已經 考慮了很多。
希望大家可以使用到。
推薦一個連線:
華為推送 超級多問題 都在這裡 。