三分钟帮你集成极光推送——和那些你可能不知道的事

简介: 本文简介:本文前篇,可以帮助朋友们快速集成极光推送。本文后篇,是我自己项目实践的一些总结和心得,应该对读者们还是很有参考价值的,相信读完这篇文章,你会对极光推送有更加深入的理解,而不仅仅只是会集成而已。

本文简介:本文前篇,可以帮助朋友们快速集成极光推送。本文后篇,是我自己项目实践的一些总结和心得,应该对读者们还是很有参考价值的,相信读完这篇文章,你会对极光推送有更加深入的理解,而不仅仅只是会集成而已。总之呢,集成第三方SDK,都不是很难的事情,仔细阅读文档,一步步来,遇到Bug,慢慢解决就行,实在解决不了,可以问问客服小哥哥或者小姐姐,重要的是,你得有着解决它的决心和耐心。

《一》JPush SDK的集成

简要介绍:
极光推送(JPush)是一个端到端的推送服务,使得服务器端消息能够及时地推送到终端用户手机上,让开发者积极地保持与用户的连接,从而提高用户活跃度、提高应用的留存率。

开发者集成 JPush Android SDK 到其应用里,JPush Android SDK 创建到 JPush Cloud 的长连接,为 App 提供永远在线的能力。 当开发者想要及时地推送消息到达 App 时,只需要调用 JPush API 推送,或者使用其他方便的智能推送工具,即可轻松与用户交流。
JPush Android SDK 是作为 Android Service 长期运行在后台的,从而创建并保持长连接,保持永远在线的能力。

假设你已经注册了极光的账号,登录进来了。点击立即体验,创建自己的应用。


img_fd763efcd717770649e38dcdf9e6d0a6.png
image.png
img_b10fd3e208c9c4a9ffca4031269566dd.png
image.png

App端集成需要用到的AppKey。


img_d9632deec4f6279e4149c666585edf13.png
image.png

添加集成代码,此处使用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.** { *; }

七、通过极光官网控制台推送,测试推送结果。


img_64ac3d1cecc2c49488de7a59edc55268.png
image.png

《二》推送方式分析

使用场景分析:推送消息,无疑就是两种情形,一种是全部推送,这种方式简单,群发就行了,Portal与API都支持向指定的 appKey 群发消息。但是一般实际的业务需求,都不仅仅是群发,还需要针对某一个人或者某一群人进行推送。例如:给会员推送一些新的内容,此时就需要针对会员这一群特定的人,来进行推送。简单的说,就是需要把JPush的注册用户与开发者App用户绑定起来,以达到精准推送的目的。

1.RegistrationID方式实现点对点的精准推送(把绑定关系保存到开发者应用服务器中)

集成了 JPush SDK 的应用程序在第一次成功注册到 JPush 服务器时,JPush 服务器会以广播的形式发送RegistrationID到应用程序,给客户端返回一个唯一的该设备的标识 - RegistrationID。首次注册成功,自定义的MyReceiver中会收到一条广播。

如下图,会在MyReceiver中收到RegistrationID的值。只要极光推送第一次注册成功了,后期不会再发 RegistrationID 的广播了。RegistrationID 就会被保留在手机内,下次即使你是无网状态进入APP,你也可以获取到这个RegistrationID。有了这个标识,App 编程可以把这个 RegistrationID 保存到自己的应用服务器上,然后就可以根据 RegistrationID 来向设备推送消息或者通知。所以建议可以在你的Application和MyReceiver中都对这个RegistrationID进行赋值。然后根据项目的业务需要,将RegistrationID和用户标识的对应关系,上传自己的服务端。


img_7a420cf9fc1d85c7edc95bc1b72d8858.png
image.png
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:
    // 建议这里往 SharePreference 里写一个成功设置的状态。成功设置一次后,以后不必再次设置了。
                    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-\u9FA50-9a-zA-Z_!@#$&*+=.|]+$");
        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 关于App被杀死后,如何接收极光推送
阅读参考:
官网集成
极光推送Android端API
详解极光推送的 4 种消息形式 —— Android 篇
常见问题 - JPush 合集(持续更新)

相关文章
|
Android开发 iOS开发
集成极光推送-服务端
集成极光推送-服务端
集成极光推送-服务端
极光推送集成
极光推送集成(一)极光推送集成(二)极光推送集成(三)极光推送集成(四)极光推送集成(五)极光推送集成(六)极光推送集成(七)极光推送集成(八)—— 工程实践
1282 0
|
开发工具 Android开发 开发者
极光推送(一)集成
一. 概述 image 开发者集成 JPush Android SDK 到其应用里,JPush Android SDK 作为 Android Service 长期运行在后台为APP提供永久在线的能力并保持与JPush Cloud 的长连接,当开发者想要及时地推送消息到达 App 时,只需要调用 JPush API 推送,或者使用其他方便的智能推送工具,即可轻松与用户交流。
1329 0
|
Android开发 Java 开发工具
Android开发之极光推送的集成
客户器端集成 1、注册app,生成appKey 和 Master Secret 注册app.png 2、导入SDK开发包到你自己的应用程序项目 配置sdk.
861 0
|
Java API
JPush极光推送自己集成服务端jar包
极光推送服务端的api太多,自己把他封装了个jar包,有兴趣的可以看看,源码和jar包都有。 源码:http://download.csdn.net/detail/z745968621/8231145 jar包:http://download.
1206 0
|
API iOS开发
|
4月前
|
监控 druid Java
spring boot 集成配置阿里 Druid监控配置
spring boot 集成配置阿里 Druid监控配置
288 6
|
4月前
|
Java 关系型数据库 MySQL
如何实现Springboot+camunda+mysql的集成
【7月更文挑战第2天】集成Spring Boot、Camunda和MySQL的简要步骤: 1. 初始化Spring Boot项目,添加Camunda和MySQL驱动依赖。 2. 配置`application.properties`,包括数据库URL、用户名和密码。 3. 设置Camunda引擎属性,指定数据源。 4. 引入流程定义文件(如`.bpmn`)。 5. 创建服务处理流程操作,创建控制器接收请求。 6. Camunda自动在数据库创建表结构。 7. 启动应用,测试流程启动,如通过服务和控制器开始流程实例。 示例代码包括服务类启动流程实例及控制器接口。实际集成需按业务需求调整。
367 4
|
4月前
|
消息中间件 Java 测试技术
【RocketMQ系列八】SpringBoot集成RocketMQ-实现普通消息和事务消息
【RocketMQ系列八】SpringBoot集成RocketMQ-实现普通消息和事务消息
317 1
|
5月前
|
消息中间件 Java Kafka
springboot集成kafka
springboot集成kafka
168 2

热门文章

最新文章