1. 程式人生 > >三分鐘幫你整合極光推送——和那些可能你不知道的事

三分鐘幫你整合極光推送——和那些可能你不知道的事

本文簡介:本文前篇,可以幫助朋友們快速整合極光推送。本文後篇,是我自己專案實踐的一些總結和心得,應該對讀者們還是很有參考價值的,相信讀完這篇文章,你會對極光推送有更加深入的理解,而不僅僅只是會整合而已。總之呢,整合第三方SDK,都不是很難的事情,仔細閱讀文件,一步步來,遇到Bug,慢慢解決就行,實在解決不了,可以問問客服小哥哥或者小姐姐,重要的是,你得有著解決它的決心和耐心。
《一》JPush SDK的整合
簡要介紹:
極光推送(JPush)是一個端到端的推送服務,使得伺服器端訊息能夠及時地推送到終端使用者手機上,讓開發者積極地保持與使用者的連線,從而提高使用者活躍度、提高應用的留存率。

開發者整合 JPush Android SDK 到其應用裡,JPush Android SDK 建立到 JPush Cloud 的長連線,為 App 提供永遠線上的能力。 當開發者想要及時地推送訊息到達 App 時,只需要呼叫 JPush API 推送,或者使用其他方便的智慧推送工具,即可輕鬆與使用者交流。
JPush Android SDK 是作為 Android Service 長期執行在後臺的,從而建立並保持長連線,保持永遠線上的能力。

假設你已經註冊了極光的賬號,登入進來了。點選立即體驗,建立自己的應用。



App端整合需要用到的AppKey。


新增整合程式碼,此處使用jcenter的方式整合。
一、確認android studio的 Project 根目錄的主 gradle 中配置了jcenter支援。(新建project預設配置就支援)
buildscript {
    repositories {
        jcenter()
    }
    ......
}


allprojets {
    repositories {
        jcenter()
    }
}
二、在 module 的 gradle 中新增依賴和AndroidManifest的替換變數。
android {
    ......
    defaultConfig {
        applicationId "com.xxx.xxx" //JPush上註冊的包名.
        ......


        ndk {
            //選擇要新增的對應cpu型別的.so庫。
            abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a'
            // 還可以新增 'x86', 'x86_64', 'mips', 'mips64'
        }


        manifestPlaceholders = [
            JPUSH_PKGNAME : applicationId,
            JPUSH_APPKEY : "你的appkey", //JPush上註冊的包名對應的appkey.
            JPUSH_CHANNEL : "developer-default", //暫時填寫預設值即可.
        ]
        ......
    }
    ......
}


dependencies {
    ......


    compile 'cn.jiguang.sdk:jpush:3.1.1'  // 此處以JPush 3.1.1 版本為例。
    compile 'cn.jiguang.sdk:jcore:1.1.9'  // 此處以JCore 1.1.9 版本為例。
    ......
}
三、AndroidManifest.xml中新增
  <!--Jpush配置 所需許可權start-->
    <!-- Required -->
    <permission
        android:name="你的應用包名.permission.JPUSH_MESSAGE"
        android:protectionLevel="signature" />


    <!-- Required  一些系統要求的許可權,如訪問網路等-->
    <uses-permission android:name="你的應用包名.permission.JPUSH_MESSAGE" />
    <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" />
    <!--<uses-permission android:name="android.permission.INTERNET" />-->
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <!--<uses-permission android:name="android.permission.READ_PHONE_STATE" />-->
    <!--<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />-->
    <!--<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />-->
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <!--<uses-permission android:name="android.permission.VIBRATE" />-->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <!--<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />-->
    <!--<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />-->


    <!-- Optional for location -->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!-- 用於開啟 debug 版本的應用在6.0 系統上 層疊視窗許可權 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <!--<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />-->
    <!--<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />-->
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
    <!--<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />-->
    <!--<uses-permission android:name="android.permission.GET_TASKS" />-->
    <!--Jpush配置 所需許可權end-->


    <!--Jpush配置 start-->
    <application
        <!-- Rich push 核心功能 since 2.0.6-->
        <activity
            android:name="cn.jpush.android.ui.PopWinActivity"
            android:theme="@style/MyDialogStyle"
            android:exported="false">
        </activity>


        <!-- Required SDK核心功能-->
        <activity
            android:name="cn.jpush.android.ui.PushActivity"
            android:configChanges="orientation|keyboardHidden"
            android:theme="@android:style/Theme.NoTitleBar"
            android:exported="false">
            <intent-filter>
                <action android:name="cn.jpush.android.ui.PushActivity" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="你的應用包名" />
            </intent-filter>
        </activity>


        <!-- Required SDK 核心功能-->
        <!-- 可配置android:process引數將PushService放在其他程序中 -->
        <service
            android:name="cn.jpush.android.service.PushService"
            android:enabled="true"
            android:exported="false">
            <intent-filter>
                <action android:name="cn.jpush.android.intent.REGISTER" />
                <action android:name="cn.jpush.android.intent.REPORT" />
                <action android:name="cn.jpush.android.intent.PushService" />
                <action android:name="cn.jpush.android.intent.PUSH_TIME" />
            </intent-filter>
        </service>
        <!-- since 3.0.9 Required SDK 核心功能-->
        <provider
            android:authorities="你的應用包名.DataProvider"
            android:name="cn.jpush.android.service.DataProvider"
            android:exported="false"
            />


        <!-- since 1.8.0 option 可選項。用於同一裝置中不同應用的JPush服務相互拉起的功能。 -->
        <!-- 若不啟用該功能可刪除該元件,將不拉起其他應用也不能被其他應用拉起 -->
        <service
            android:name="cn.jpush.android.service.DaemonService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="cn.jpush.android.intent.DaemonService" />
                <category android:name="你的應用包名" />
            </intent-filter>


        </service>
        <!-- since 3.1.0 Required SDK 核心功能-->
        <provider
            android:authorities="你的應用包名.DownloadProvider"
            android:name="cn.jpush.android.service.DownloadProvider"
            android:exported="true"
            />
        <!-- Required SDK核心功能-->
        <receiver
            android:name="cn.jpush.android.service.PushReceiver"
            android:enabled="true"
            android:exported="false">
            <intent-filter android:priority="1000">
                <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED_PROXY" />   <!--Required  顯示通知欄 -->
                <category android:name="你的應用包名" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.USER_PRESENT" />
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
            <!-- Optional -->
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_ADDED" />
                <action android:name="android.intent.action.PACKAGE_REMOVED" />


                <data android:scheme="package" />
            </intent-filter>
        </receiver>


        <!-- Required SDK核心功能-->
        <receiver android:name="cn.jpush.android.service.AlarmReceiver" android:exported="false"/>


        <!-- User defined.  For test only  MyReceiver為使用者自定義的廣播接收器-->
        <receiver
            android:name=".util.MyReceiver"
            android:exported="false"
            android:enabled="true">
            <intent-filter>
                <action android:name="cn.jpush.android.intent.REGISTRATION" /> <!--Required  使用者註冊SDK的intent-->
                <action android:name="cn.jpush.android.intent.MESSAGE_RECEIVED" /> <!--Required  使用者接收SDK訊息的intent-->
                <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED" /> <!--Required  使用者接收SDK通知欄資訊的intent-->
                <action android:name="cn.jpush.android.intent.NOTIFICATION_OPENED" /> <!--Required  使用者開啟自定義通知欄的intent-->
                <action android:name="cn.jpush.android.intent.CONNECTION" /><!-- 接收網路變化 連線/斷開 since 1.6.3 -->
                <category android:name="你的應用包名" />
            </intent-filter>
        </receiver>


        <!-- Required  . Enable it you can get statistics data with channel -->
        <meta-data android:name="JPUSH_CHANNEL" android:value="developer-default"/>
        <meta-data android:name="JPUSH_APPKEY" android:value="應用的Appkey" /> <!--  </>值來自開發者平臺取得的AppKey-->
    </application>
        <!--Jpush配置 end-->
四、自定義一個廣播接收器MyReceiver(此處直接使用官方Demo中的MyReceiver)
/**
 * 自定義接收器
 * 
 * 如果不定義這個 Receiver,則:
 * 1) 預設使用者會開啟主介面
 * 2) 接收不到自定義訊息
 */
public class MyReceiver extends BroadcastReceiver {
	private static final String TAG = "JIGUANG-Example";


	@Override
	public void onReceive(Context context, Intent intent) {
		try {
			Bundle bundle = intent.getExtras();
			Logger.d(TAG, "[MyReceiver] onReceive - " + intent.getAction() + ", extras: " + printBundle(bundle));


			if (JPushInterface.ACTION_REGISTRATION_ID.equals(intent.getAction())) {
				String regId = bundle.getString(JPushInterface.EXTRA_REGISTRATION_ID);
				Logger.d(TAG, "[MyReceiver] 接收Registration Id : " + regId);
				//send the Registration Id to your server...


			} else if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {
				Logger.d(TAG, "[MyReceiver] 接收到推送下來的自定義訊息: " + bundle.getString(JPushInterface.EXTRA_MESSAGE));
				processCustomMessage(context, bundle);


			} else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(intent.getAction())) {
				Logger.d(TAG, "[MyReceiver] 接收到推送下來的通知");
				int notifactionId = bundle.getInt(JPushInterface.EXTRA_NOTIFICATION_ID);
				Logger.d(TAG, "[MyReceiver] 接收到推送下來的通知的ID: " + notifactionId);


			} else if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) {
				Logger.d(TAG, "[MyReceiver] 使用者點選打開了通知");


				//開啟自定義的Activity
				Intent i = new Intent(context, TestActivity.class);
				i.putExtras(bundle);
				//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP );
				context.startActivity(i);


			} else if (JPushInterface.ACTION_RICHPUSH_CALLBACK.equals(intent.getAction())) {
				Logger.d(TAG, "[MyReceiver] 使用者收到到RICH PUSH CALLBACK: " + bundle.getString(JPushInterface.EXTRA_EXTRA));
				//在這裡根據 JPushInterface.EXTRA_EXTRA 的內容處理程式碼,比如開啟新的Activity, 開啟一個網頁等..


			} else if(JPushInterface.ACTION_CONNECTION_CHANGE.equals(intent.getAction())) {
				boolean connected = intent.getBooleanExtra(JPushInterface.EXTRA_CONNECTION_CHANGE, false);
				Logger.w(TAG, "[MyReceiver]" + intent.getAction() +" connected state change to "+connected);
			} else {
				Logger.d(TAG, "[MyReceiver] Unhandled intent - " + intent.getAction());
			}
		} catch (Exception e){


		}


	}


	// 列印所有的 intent extra 資料
	private static String printBundle(Bundle bundle) {
		StringBuilder sb = new StringBuilder();
		for (String key : bundle.keySet()) {
			if (key.equals(JPushInterface.EXTRA_NOTIFICATION_ID)) {
				sb.append("\nkey:" + key + ", value:" + bundle.getInt(key));
			}else if(key.equals(JPushInterface.EXTRA_CONNECTION_CHANGE)){
				sb.append("\nkey:" + key + ", value:" + bundle.getBoolean(key));
			} else if (key.equals(JPushInterface.EXTRA_EXTRA)) {
				if (TextUtils.isEmpty(bundle.getString(JPushInterface.EXTRA_EXTRA))) {
					Logger.i(TAG, "This message has no Extra data");
					continue;
				}


				try {
					JSONObject json = new JSONObject(bundle.getString(JPushInterface.EXTRA_EXTRA));
					Iterator<String> it =  json.keys();


					while (it.hasNext()) {
						String myKey = it.next();
						sb.append("\nkey:" + key + ", value: [" +
								myKey + " - " +json.optString(myKey) + "]");
					}
				} catch (JSONException e) {
					Logger.e(TAG, "Get message extra JSON error!");
				}


			} else {
				sb.append("\nkey:" + key + ", value:" + bundle.getString(key));
			}
		}
		return sb.toString();
	}
	
	//send msg to MainActivity
	private void processCustomMessage(Context context, Bundle bundle) {
		if (MainActivity.isForeground) {
			String message = bundle.getString(JPushInterface.EXTRA_MESSAGE);
			String extras = bundle.getString(JPushInterface.EXTRA_EXTRA);
			Intent msgIntent = new Intent(MainActivity.MESSAGE_RECEIVED_ACTION);
			msgIntent.putExtra(MainActivity.KEY_MESSAGE, message);
			if (!ExampleUtil.isEmpty(extras)) {
				try {
					JSONObject extraJson = new JSONObject(extras);
					if (extraJson.length() > 0) {
						msgIntent.putExtra(MainActivity.KEY_EXTRAS, extras);
					}
				} catch (JSONException e) {


				}


			}
			LocalBroadcastManager.getInstance(context).sendBroadcast(msgIntent);
		}
	}
}

五、在Application中的onCreate()方法中初始化極光推送

   // 初始化 JPush
        JPushInterface.init(this);
        //釋出時關閉日誌
        JPushInterface.setDebugMode(false);

六、最後不要忘了新增混淆程式碼哦!

請在工程的混淆檔案proguard-rules.pro中新增以下配置:
-dontoptimize
-dontpreverify


-dontwarn cn.jpush.**
-keep class cn.jpush.** { *; }
-keep class * extends cn.jpush.android.helpers.JPushMessageReceiver { *; }


-dontwarn cn.jiguang.**
-keep class cn.jiguang.** { *; }

七、通過極光官網控制檯推送,測試推送結果。




《二》推送方式分析

使用場景分析:推送訊息,無疑就是兩種情形,一種是全部推送,這種方式簡單,群發就行了,Portal與API都支援向指定的 appKey 群發訊息。但是一般實際的業務需求,都不僅僅是群發,還需要針對某一個人或者某一群人進行推送。例如:給會員推送一些新的內容,此時就需要針對會員這一群特定的人,來進行推送。簡單的說,就是需要把JPush的註冊使用者與開發者App使用者繫結起來。JPush給了我們以下兩種方式來實現。


1.RegistrationID方式實現點對點的精準推送(把繫結關係儲存到開發者應用伺服器中)

集成了 JPush SDK 的應用程式在第一次成功註冊到 JPush 伺服器時,JPush 伺服器會以廣播的形式傳送RegistrationID到應用程式,給客戶端返回一個唯一的該裝置的標識 - RegistrationID。首次註冊成功,自定義的MyReceiver中會收到一條廣播。

如下圖,會在MyReceiver中收到RegistrationID的值。只要極光推送第一次註冊成功了,後期不會再發 RegistrationID 的廣播了。RegistrationID 就會被保留在手機內,下次即使你是無網狀態進入APP,你也可以獲取到這個RegistrationID。有了這個標識,App 程式設計可以把這個 RegistrationID 儲存到自己的應用伺服器上,然後就可以根據 RegistrationID 來向裝置推送訊息或者通知。所以建議可以在你的Application和MyReceiver中都對這個RegistrationID進行賦值。然後根據專案的業務需要,將RegistrationID和使用者標識的對應關係,上傳自己的服務端。

public class MyApplication extends Application{
    public static String registrationID;
     @Override
    public void onCreate() {
        // 初始化 JPush
        JPushInterface.init(this);
        registrationID = JPushInterface.getRegistrationID(this);
        Log.d("TAG", "接收Registration Id : " + registrationID);
    }
}
【注意】:
如果 App 不解除安裝,是直接覆蓋安裝,Android, iOS 上 RegistrationID 的值都不會變化。
如果 App 是解除安裝之後再次安裝:Android 上 RegistrationID 基本不會變;
iOS 上如果啟用了 IDFA 變化可能性不大,如果未啟用 IDFA 則每次安裝 RegistrationID 都會變;
參考:極光推送裝置唯一性標識RegistrationID

如果使用此種推送方式,你可能會遇到的問題:假設在一個裝置中登入不同的賬號,那此時上傳給伺服器的都是同一個RegistrationID,因為裝置沒有變化。那麼可能出現:本來伺服器是根據A使用者找到它的RegistrationID進行推送,但是B使用者也是在A使用者登入的裝置登入的,RegistrationID跟A的一樣,這樣就導致B使用者收到了推送給A使用者的推送內容。

需要謹記:

使用 RegistrationID 推送的關鍵於,App 開發者需要在開發 App 時,獲取到這個 RegistrationID,儲存到 App 業務伺服器上去,並且與自己的使用者標識對應起來。建議 App 開發者儘可能做這個儲存動作。因為這是最精確地定位到裝置的。(RegistrationID 的方式,相對而言比較麻煩一點,因為需要自己的App服務端維護RegistrationID和使用者的對應關係。暫時我還沒有使用這種方式,真正投入到線上的專案,只是測試環境下除錯過。)
值得一讀:推送方式


2.別名與標籤推送(把繫結關係儲存到 JPush 伺服器端)

別名推送也是一種實現點對點推送的方式,用於給某特定使用者推送訊息。
功能介紹:
①為安裝了應用程式的使用者,取個別名來標識。以後給該使用者 Push 訊息時,就可以用此別名來指定。
②每個使用者只能指定一個別名。
③同一個應用程式內,對不同的使用者,建議取不同的別名。這樣,儘可能根據別名來唯一確定使用者。
④系統不限定一個別名只能指定一個使用者。如果一個別名被指定到了多個使用者,當給指定這個別名發訊息時,伺服器端API會同時給這多個使用者傳送訊息。


舉例:在一個使用者要登入的遊戲中,可能設定別名為 userid。遊戲運營時,發現該使用者 3 天沒有玩遊戲了,則根據 userid 呼叫伺服器端API發通知到客戶端提醒使用者。


別名設定:

需要和自己的服務端協商好別名的規則,例如下面的程式碼中,是將使用者ID通過MD5加密,作為別名,設定儲存到JPush伺服器。當然你也可以使用其他的拼接規則,具體根據每個公司的專案需要設定即可,只要滿足別名的命名限制就行: 命名長度限制為 40 位元組。(判斷長度需採用UTF-8編碼)


深入理解各種推送方式可以參考:推送方式

下面是一個JPush設定別名和標籤的輔助類。
public class JPushHelper {
    private String TAG = "JPushHelper";


    /**
     * 設定別名與標籤
     *
     * @param UUID
     */
    private void setAlias(String UUID) {
        if (null != UUID) {
            //恢復接收推送
            JPushInterface.resumePush(MyApplication.getInstance());
            JPushInterface.setAliasAndTags(MyApplication.getInstance(), UUID, null, mAliasCallback);
        }
    }


    public void setAlias() {
        if (MyApplication.isLogin) { //必須登入
            UserInfo userBean = ACT_Login.getLoginUser();
            if (null != userBean) {
                 //根據具體業務需求,可以再拼接上其他相關欄位
                //String alias = "";
                //StringBuilder stringBuffer = new StringBuilder();
                // stringBuffer.append(StringUtil.getString(userBean.user_id));
                Log.e(TAG, stringBuffer.toString());
                alias = MD5Util.string2MD5(userBean.user_id);
                //限制:alias 命名長度限制為 40 位元組。(判斷長度需採用UTF-8編碼)
                Log.e(TAG, alias);
                setAlias("");
                setAlias(alias);
            }
        }
    }


    /**
     * 清除設定別名與標籤,停止接收推送
     */
    public void removeAlias() {
        JPushInterface.clearAllNotifications(MyApplication.getInstance());
        setAlias("");
        JPushInterface.stopPush(MyApplication.getInstance());
    }


    private final TagAliasCallback mAliasCallback = new TagAliasCallback() {


        @Override
        public void gotResult(int code, String alias, Set<String> tags) {
            String logs;
            switch (code) {
                case 0:
                    logs = "Set tag and alias success";
                    Log.e(TAG, logs);
                    break;
                case 6002:
                    logs = "Failed to set alias and tags due to timeout. Try again after 60s.";
                    // 延遲 60 秒來呼叫 Handler 設定別名
                    mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SET_ALIAS, alias), 1000 * 6);
                    Log.e(TAG, logs + AppDateUtil.getTimeStamp(System.currentTimeMillis(), AppDateUtil.MM_DD_HH_MM_SS));
                    break;
                default:
                    logs = "Failed with errorCode = " + code;
                    Log.e(TAG, logs);
            }


        }


    };


    private static final int MSG_SET_ALIAS = 1001;
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(android.os.Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MSG_SET_ALIAS:
                    Log.e(TAG, "Set alias in handler." + ((String) msg.obj));
                    // 呼叫 JPush 介面來設定別名。
                    JPushInterface.setAliasAndTags(MyApplication.getInstance(),
                            (String) msg.obj,
                            null,
                            mAliasCallback);
                    break;
                default:
                    Log.e(TAG, "Unhandled msg - " + msg.what);
            }
        }
    };


    // 校驗Tag Alias 只能是數字,英文字母和中文
    public static boolean isValidTagAndAlias(String s) {
        Pattern p = Pattern.compile("^[\u4E00-\[email protected]#$&*+=.|]+$");
        Matcher m = p.matcher(s);
        return m.matches();
    }
}

3.關於後端伺服器設定別名還是前端設定別名:

說實在的,以前沒有遇到過這個選擇題,因為之前做的極光推送都是在我們客戶端設定,不過最近除錯JPush的時候後臺說他設定別名,我突然就有點蒙了?不是一般都是前端設定嗎???
於是有個疑問:如果是服務端設定別名,那服務端也沒有經過客戶端,那極光伺服器咋通過別名來匹配使用者進行點對點推送呀???我一下子有點想不通了。然後查了一下文件和相關部落格,確實極光伺服器也給後端服務提供設定別名的API,又問了一下後端開發,他是不是隻是單單設定了別名,還是在裝置ID上也有做了處理,因為沒有對映關係,極光伺服器也不可能找到對應的使用者進行推送呀。果不其然,他是在RegistrationID上設定的別名,這下我就明白了。
不過大部分的情況,應該還是前端設定別名吧,畢竟那些登入登出的操作在前端控制會比較方便。

小提醒:

實際應用場景,客戶端一般都需要在登入到App成功後,設定別名,恢復接收推送。退出登入後,清除別名,停止接收推送。

恢復接收推送:

 JPushInterface.resumePush(MyApplication.getInstance());

停止接收推送:

JPushInterface.stopPush(MyApplication.getInstance());

4.App殺死後還想要收到推送

有的公司由於業務需求,可能會要求你,App殺死後還想要收到推送。如果知道JPush Android SDK 是作為 Android Service 長期執行在後臺的,從而建立並保持長連線,保持永遠線上的能力...的童鞋們,那麼必須要清楚一點的是:如果APP真的被殺死了,是不可能收到推送的,如果殺死了還能收到,那說明可能是以下幾種情況:
①應用自啟動了
②要麼是其他方式將App拉起來了。
③你壓根就沒有殺死App,Service還在執行著。(有的手機清理App,並沒有完全殺死程序的)
閱讀參考:
官網整合
極光推送Android端API

相關推薦

分鐘整合極光——那些可能知道

本文簡介:本文前篇,可以幫助朋友們快速整合極光推送。本文後篇,是我自己專案實踐的一些總結和心得,應該對讀者們還是很有參考價值的,相信讀完這篇文章,你會對極光推送有更加深入的理解,而不僅僅只是會整合而已。總之呢,整合第三方SDK,都不是很難的事情,仔細閱讀文件,一步步來,遇到B

Android整合極光踩過的坑(一)

轉載請標明出處 整合步驟以及整合過程遇到的坑: 這部分主要闡述了整合極光推送的sdk的步驟,以及我在整合過程中遇到的一些問題。整合步驟只是摘出了極光SDK中必須的骨子的部分,可以滿足一般專案Push需求,這裡只做了通知訊息,自定義的穿透訊息請詳見極光的SDK整合文件

整合極光 定時

前端,後端,極光推送之間的邏輯關係 (誤區:php與前端app要對接,其實不要直接對接,php直接呼叫極光伺服器就可以了)   一、安裝jpush 極光推送  在composer的配置檔案中加入 "require": {   "jpush/jp

ionic 1,2 整合極光

專案用到極光推送,在此做個總結,以免忘記! 首先,這肯定要用到cordova的jpush外掛,這個外掛跟cordova整合的百度定位外掛有點衝突,需注意! 去極光官網申請appkey,這是必須的; 然後add此外掛,帶上appkey; 好了,在app.js檔案初始化,定義方法,程式碼

Android快速整合極光,內含自定義通知,通知物件到某一個人,或者某一群人

整合極光推送 使用jcenter 自動整合步驟 說明 : 使用 jcenter 自動整合,不需要在專案中新增 jar 和 so,jcenter 會自動完成依賴;在 AndroidManifest.xml 中不需要新增任何 JPush SDK 相關的配置,jcen

Swift 3.0 整合極光

1.前言 推送證書配置什麼的都不多講了,極光推送的開發文件裡都有詳細的介紹極光推送文件,因為官方的文件是OC版本的,我這裡主要是講解一下怎麼用Swift進行整合。 本篇文章也可移步簡書閱覽,效果更好哦! 2.配置 現在一切都已經根據他們的文件配置好了

AndroidStudio整合極光

本人學習筆記,新手可以學習,高手請避讓擼程式碼去 廢話不說,開始擼程式碼。 1、去鐳射推送官網去註冊賬號,認證身份。 https://www.jpush.cn/ 2、點選建立應用建立自己的應用。 根

關於整合極光的坑

1、根據文件使用自動整合, 需要在AndroidManifest.xml中加入下列程式碼(加粗部分) <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.androi

java+maven整合極光服務

       最近有不少想寫想記的東西,可惜最近公司太忙,還有就是我比較懶,一到家裡就不行動了。行了,今天主要是整合極光服務的及時通訊功能,直接記下來好了 我的JAVA專案主要是需要整合極光的推送訊息給android的方,所以可能我只會介紹怎麼給極光推送。

ThinkPHP框架整合極光DEMO

     極光推送(JPush)是獨立的第三方雲推送平臺,致力於為全球移動應用開發者提供專業、高效的移動訊息推送服務。     本篇博文講述如何在將極光推送DEMO整合到ThinkPHP框架中,我使用的是極光推送PHP_DEMO_V3.4.3版本:     1、將極光

React Native 整合極光 JPush出現的一些么蛾子

Xcode報錯 error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: can’t locate fi

iOS整合極光 通知 自定義訊息

支援的版本 r1.2.5 以後。 功能說明 只有在前端執行的時候才能收到自定義訊息的推送。 從jpush伺服器獲取使用者推送的自定義訊息的內容、標題、附件欄位等。 實現方法 獲取iOS的推送內容需要在delegate類中註冊通知並實現回撥方法。 1、在方法-

使用android studio整合極光

1.下載sdk http://docs.jiguang.cn/resources/ 2.解壓下載的壓縮包 點選開啟libs,如下圖: 我把資料夾中的內容分成了兩部分,以便下面用。接下來建一個名為

Android整合極光踩坑(二)升級篇

轉載請標明出處 前言 前段時間針對整合極光推送寫了篇文章( Android整合極光推送和踩過的坑),後來提測以後發現了各種問題。一直沒時間總結一下,趁著週末有點時間,趕緊把這段時間裡針對Push這塊兒遇到的問題梳理一下。並且對上篇文章 《Android整合極光推

Eclipse Android開發整合極光

今天上午閒來無事,想起還沒做過推送。去官網準備整合環境。看了下是android studio的,我就沒往下看。百度了幾篇文章,硬是沒弄出來,主要是百度的文章比較舊,和現在的sdk有區別。所幸我已經完美繼承,特此寫一篇繼承文件給剛準備入坑的小夥伴。第一步:進入極光推送官網。註冊

ionic整合極光外掛-iOS

DEMO地址https://github.com/JsonJieLi/cordova-jpushDemo/tree/master 1.首先建立一個ionic的專案 前面有介紹不詳細說了也可以參考官方網

整合極光後,根據不同內容跳轉App相應的頁面

前言:由於某push到達率問題,所以我們決定換成口碑較高的極光推送,在此梳理一下完成過程,小菜鳥剛剛起步,不足之處還請各位多多指教~ 需求:1.整合極光推送 2.根據推送內容的不同跳轉相應的頁面,也就是獲取推送內容並作出處理(非官網中所

swift3.0 整合極光(v2.2)iOS10.0最新寫法

// // AppDelegate.swift // 1120-jiguang // // Created by targetcloud on 2016/11/20. // Copyright © 2016年 targetcloud. All rights rese

iOS整合極光 生產環境收訊息

但是! 怎麼會那麼順利嘛,問題接踵而至!由於要給裝置傳送自定義訊息來通知使用者在其他裝置登入,這裡就需要一個唯一的識別符號,可以用tags(NSeet型別標籤)、或者a’lias。 [JPUSHService setTags:nil alias:str c

Android Studio整合極光(Jpush) 報錯 java.lang.UnsatisfiedLinkError: cn.jpush.android.service.PushProtoco

Android studio 整合極光推送(Jpush) (華為手機)報錯, E/JPush: [JPushGlobal] Get sdk version fail![獲取sdk版本失敗!] W/System.err: java.lang.UnsatisfiedLinkError: cn.jpush.a