Notification点击跳转指定界面(APP被杀死或双击退出时唤醒,然后跳转)

现有如下需求:
后台做一个推送,APP收到后以notification的形式展示,用户点击,跳转到指定界面。

需求简单,但是有些细节,确是要在写的时候,通过大量测试才能知道。
1、如果用户双击退出了,这个时候,APP并没有被系统杀死,点击手机上的菜单键,可以看到它还在系统中存活着,这个时候,如果点击notification去跳转指定界面(如:Activity1),会直接打开,但是用户点击返回键的时候,会立刻结束这个Activity,回到手机桌面。
2、如果用户在APP被清理、杀死的情况下收到推送,展示了一个notification(用三方的可以做到这样),这个时候用户点击,会唤醒APP,但是最后停到APP首页,并没有去指定界面。

经过测试今日头条美团的notification消息(有了推送不立刻点,调整到我想要的状态再去点击),模拟的写了个处理方法,最后效果差不多

要跳转的界面,肯定不止一个,暂定3个Activity,1-3,创建一个bean,创建跳转工具类等进行操作。

特别注意!
特别注意!
特别注意!
本来这个说明,计划写在最后,不过担心看到下面就没耐心了,就提前到前面!
说明:
注意清单文件中,唤醒中转界面:AwakeTempActivity的启动模式,是android:launchMode=”singleTask”。不要用默认的。
经大量测试发现,以下情况,点通知栏不会跳转,需要这样设置AwakeTempActivity的启动模式才能解决
1、(此方法复现率100%)启动APP,双击退出(不要杀死),后台推送2条(及以上),手机上点击其中一条,APP被唤醒并去到指定界面,然后点击其他通知,不会跳转;
2、(此方法复现率很高)启动APP,双击退出(不要杀死),后台推送,手机收到后,启动APP,APP稳定到首页后,点击收到的推送,此时不会跳转到指定界面

其他:
目前我知道的,有5种方法可以唤醒指定APP:h5唤醒,需要清单文件中做一定的配置,这个我在前面博客中写过,不多说了;广播(如果用notification,因为有PendingIntent,发广播貌似效果不好(我没测试错误的话))。剩下的3种,在AwakeTempActivity中都提到了。需要注意的是,第二种方法,需要清单文件中做一些设置,配合使用(详见注释以及下面代码)。其他的不用。

目录结构:
这里写图片描述

说明:
Activity1-3,是要去的目标页面,其中,Activity_2特殊,在那个界面,就算收到消息,也不做提示和展示,用于模拟特殊界面

代码实现:
Activity1-3,是测试的,不做多余操作。他们3个的代码一样

package com.chen.demo2;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;

public class Activity_1 extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }

}

MyApplication

package com.chen.demo2;

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;


public class MyApplication extends Application {

    private Activity app_activity = null;

    private static MyApplication mContext = null;

    @Override
    public void onCreate() {
        super.onCreate();

        mContext=this;

        initGlobeActivity();

    }

    /**
     * 获取栈顶Activity
     */
    private void initGlobeActivity() {
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            }

            @Override
            public void onActivityStarted(Activity activity) {
            }

            @Override
            public void onActivityResumed(Activity activity) {
                app_activity = activity;

            }

            @Override
            public void onActivityPaused(Activity activity) {
            }

            @Override
            public void onActivityStopped(Activity activity) {
            }

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            }

            @Override
            public void onActivityDestroyed(Activity activity) {
            }
        });
    }

    // 对外暴露上下文
    public static MyApplication getApplication() {
        return mContext;
    }

    /**
     * 公开方法,外部可通过 BaseApplication.getCurrentActivity() 获取到当前最上层的activity
     */
    public Activity getCurrentActivity() {
        return app_activity;
    }

}

工具:

package com.chen.demo2;

import android.app.Activity;
import android.content.Context;
import android.text.TextUtils;

public class Util {

    /**
     * 是否被双击退出
     */
    public static boolean isDoubleClickExit = false;

    /**
     * 用于标记APP是不是存活。
     * 在MainActivity中,置为true,表示APP已经启动。除此之外不做赋值操作。如果变成了false,表示APP被清掉了。
     */
    public static boolean isAPPAlive = false;


    public static Context getContext() {
        return MyApplication.getApplication();
    }


    /**
     * 检查字符串是否是空
     *
     * @param str
     * @return true:字符串为空
     */
    public static boolean checkStringIsEmpty(String str) {

        if (TextUtils.isEmpty(str) || "null".equals(str) || "(null)".equals(str) || "(Null)".equals(str) || "Null".equals(str) || "NULL".equals(str)) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * 是否允许处理展示消息(展示消息类型为运营的弹框消息和notification消息)
     *
     * @return 返回true,表示在不想接受展示消息的界面
     */
    public static boolean isAllowMessageShow() {

        Activity act = MyApplication.getApplication().getCurrentActivity();
        String s = "";
        if (act != null) {
            // if (act == null) 获取不到顶部的Activity,说明没有Activity启动,即。APP被杀死
            s = act.getLocalClassName();
        }
        return !checkStringIsEmpty(s) && s.contains("Activity_2");

    }
}

AwakePageInfoBean

package com.chen.demo2;

import java.io.Serializable;

/**
 * 唤醒页面,所需内容封装bean
 * chenjianqiang
 */
public class AwakePageInfoBean implements Serializable {


    //跳转类型
    /**
     * 1:去Activity_1
     * 2:去Activity_2
     * 3:去Activity_3
     */
    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

}

SharedPreferencesUtil

package com.chen.demo2;

import android.content.Context;
import android.content.SharedPreferences;


public class SharedPreferencesUtil {
    private SharedPreferences sp;
    private Context context;

    public SharedPreferencesUtil(Context context) {
        this.context = context;
    }

    /**
     * 保存唤醒APP的对象
     */
    public void saveAwakeAPPBean(AwakePageInfoBean awakePageInfoBean) {
        sp = context.getSharedPreferences("AwakeAPPBeanINFO", Context.MODE_PRIVATE);
        sp.edit().putString("awakeType", awakePageInfoBean.getType()).apply();

    }

    /**
     * 获取唤醒APP的对象
     */
    public AwakePageInfoBean getAwakeAPPBean() {
        sp = context.getSharedPreferences("AwakeAPPBeanINFO", Context.MODE_PRIVATE);
        AwakePageInfoBean awakePageInfoBean = new AwakePageInfoBean();
        awakePageInfoBean.setType(sp.getString("awakeType", ""));

        return awakePageInfoBean;
    }

    /*
    * 清空
    */
    public void deleteBrowserOpenAppBean(String name) {
        sp = context.getSharedPreferences(name, Context.MODE_PRIVATE);
        sp.edit().clear().apply();
    }

}

AwakePageUtil

package com.chen.demo2;

import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;

/**
 * 唤醒页面的工具
 */
public class AwakePageUtil {

    public static void awakePage(Context context, AwakePageInfoBean bean) {

        try {
            if (bean != null && !Util.checkStringIsEmpty(bean.getType()) && context != null) {
                //类型不为空。
                String type = bean.getType();
                Intent intent = null;

                if (TextUtils.equals("1", type)) {
                    //去展示webView的界面
                    intent = new Intent(context, Activity_1.class);
                } else if (TextUtils.equals("2", type)) {
                    //去展示webView的界面
                    intent = new Intent(context, Activity_2.class);
                } else if (TextUtils.equals("3", type)) {
                    //去展示webView的界面
                    intent = new Intent(context, Activity_3.class);
                }

                if (intent != null) {
                    context.startActivity(intent);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

AwakeTempActivity

package com.chen.demo2;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.Nullable;

/**
 * 唤醒APP的临时界面。当用户把APP杀死或者双击退出后,点击notification,先到这个界面,唤醒APP,然后再去目标界面。
 * 这样做的原因:
 * 1、假如用户双击退出APP,推送是Activity_1。这个时候,手机系统并没有杀死APP,用户点击通知栏,页面被唤醒,进行后续操作,当用户在Activity_1点击返回键,界面被销毁,直接退出程序。
 * 2、假如用户手动或者某些情况下手机系统自己杀死了APP,这个时候做推送,用户点击后,有时候仅仅是打开APP首页,不会去到目标界面。有时候不会有任何反应
 * 为了避免上述2个情况出现,在这里先判断手机状态,双击或被杀死的话,就先唤醒APP,然后再去目标界面,这样,用户点击返回键,也不会直接退出。增加用户在APP中的停留时间。
 * 2017/7/26
 * chenjianqiang
 */

public class AwakeTempActivity extends Activity {

    private AwakePageInfoBean bean;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        bean = (AwakePageInfoBean) getIntent().getSerializableExtra("AwakePageInfoBean");

        if (bean == null) {
            //bean是空,不知道目标界面,就默认唤醒APP
            PackageManager pm = getPackageManager();
            //包名
            Intent intent = pm.getLaunchIntentForPackage("com.chen.demo2");
            startActivity(intent);

            //这种唤醒方式,需要清单文件中做对应的配置,详见清单文件中,MainActivity下的<intent-filter>节点
            //            Intent intent = new Intent(AwakeTempActivity.this, MainActivity.class);
            //            intent.setAction("android.intent.chen.CALL");
            //            startActivity(intent);

            //            Intent intent = new Intent();
            //            ComponentName name = new ComponentName("com.chen.demo2"
            //                    ,"com.chen.demo2.MainActivity");
            //            intent.setComponent(name);
            //            startActivity(intent);

        } else {

            if (Util.isDoubleClickExit || !Util.isAPPAlive) {
                //处于双击退出或者APP被手机杀死情况

                SharedPreferencesUtil spu = new SharedPreferencesUtil(Util.getContext());
                spu.saveAwakeAPPBean(bean);

                PackageManager pm = getPackageManager();
                //包名
                Intent intent = pm.getLaunchIntentForPackage("com.chen.demo2");
                startActivity(intent);

                //这种唤醒方式,需要清单文件中做对应的配置,详见清单文件中,MainActivity下的<intent-filter>节点
                //                Intent intent = new Intent(AwakeTempActivity.this, MainActivity.class);
                //                intent.setAction("android.intent.chen.CALL");
                //                startActivity(intent);

                //                Intent intent = new Intent();
                //                ComponentName name = new ComponentName("com.chen.demo2"
                //                        ,"com.chen.demo2.MainActivity");
                //                intent.setComponent(name);
                //                startActivity(intent);
            } else {
                AwakePageUtil.awakePage(AwakeTempActivity.this, bean);
            }
        }

        finish();

    }


}

MainActivity

package com.chen.demo2;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;

public class MainActivity extends Activity {

    private SharedPreferencesUtil mSpu;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSpu = new SharedPreferencesUtil(Util.getContext());

        Util.isDoubleClickExit = false;
        Util.isAPPAlive = true;

    }

    @Override
    protected void onStart() {
        super.onStart();

        AwakePageInfoBean bean = mSpu.getAwakeAPPBean();
        if (bean != null && !Util.checkStringIsEmpty(bean.getType())) {
            AwakePageUtil.awakePage(MainActivity.this, bean);
        }
        mSpu.deleteBrowserOpenAppBean("AwakeAPPBeanINFO");

    }
}

MessageReceive

package com.chen.demo2;


import android.content.Context;
import android.content.Intent;

import org.json.JSONObject;

//模拟的消息push消息接收器。假的
public class MessageReceive {

    private void getPushMessaage(Context context, String message) {
        try {

            JSONObject jsonObj = new JSONObject(message);

            if (!Util.checkStringIsEmpty(jsonObj.optString("app")) && !Util.isAllowMessageShow()) {
                //所需要的数据不为空,并且,是运行接收的Activity

                JSONObject value_jo = new JSONObject(jsonObj.optString("app"));

                //类型
                String type = value_jo.optString("type");
                AwakePageInfoBean bean = new AwakePageInfoBean();
                bean.setType(type);

                Intent intent = new Intent(context, AwakeTempActivity.class);
                intent.putExtra("AwakePageInfoBean", bean);

                //把intent放到PendingIntent中,然后和Notification进行后续处理。。。。。。

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

清单文件

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.chen.demo2"
          xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>

            <!--<intent-filter>-->
                <!--<action android:name="android.intent.chen.CALL"/>-->
                <!--<category android:name="ANDROID.INTENT.CATEGORY.DEFAULT"/>-->
            <!--</intent-filter>-->

        </activity>

        <activity
            android:name=".Activity_1"
            android:screenOrientation="portrait"/>
        <activity
            android:name=".Activity_2"
            android:screenOrientation="portrait"/>
        <activity
            android:name=".Activity_3"
            android:screenOrientation="portrait"/>

        <activity
            android:name=".AwakeTempActivity"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"/>


    </application>

</manifest>

猜你喜欢

转载自blog.csdn.net/u014620028/article/details/76914337