友情提示:在看本文前,最好对友盟推送的集成文档看个差不多,不然可能有些概念不是太清楚。
友盟集成文档:https://developer.umeng.com/docs/66632/detail/98581
本文demo下载地址:https://github.com/274800562/umengtest.git
----------------分割线--------------------
应用分为在线状态和离线状态,以应用进程是否存在为判断依据。

通知分为在线通知和离线通知,同样以应用进程是否存在时为判断依据。进程存在时接收到的通知即在线通知,离线时接收到的通知为离线通知。

一 、需求描述:

1.应用离线时,收到通知,点击通知,启动应用,启动SplashActivity->MainActivity,然后根据需要跳转相应界面。

2.应用在线:
1)应用在前台时,收到通知,应用内弹框,点击跳转响应界面;
2)应用在后台时,收到通知,存储通知数据,待应用切回到前台时再弹框,点击跳转响应界面。

二、需求实现
首先,我们设定有SplashActivity、MainActivity、DetailActivity、ListActvity四个类,我们通过UMessage对象的extra字段配置数据:type,id,title等,type=1时,跳转DetailActivity;type=2时,跳转ListActvity。

3B1AAB823985FD8669D0F853FE0CF9B6.jpg

1.友盟推送可以集成厂商通道,以接收离线通知。通过继承UmengNotifyClickActivity类,重写onMessage(),点击时回调此方法。

public class UmengClickActivityextends UmengNotifyClickActivity {        private static StringTAG = UmengClickActivity.class.getName();        @Override        public void onMessage(Intent intent0) {            super.onMessage(intent0);  //此方法必须调用,否则无法统计打开数            String body = intent0.getStringExtra(AgooConstants.MESSAGE_BODY);            Log.e(TAG, "body:" + body);            Gson gson = new Gson();            UmengClickBean bean = gson.fromJson(body, UmengClickBean.class);            //ExtraBean包含三个字段:type,id,title,根据type跳转相应界面            ExtraBean extraBean = bean.getExtra();            if (null != bean) {                Intent intent = new Intent(this, SplashActivity.class);                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//必须                intent.putExtra("bean", extraBean);                intent.putExtra("tag", 1);//标志位,点击跳过去的,区别于正常逻辑跳转                startActivity(intent);                finish();             }        }}

接着,启动SplashActivity->MainActivity。

public class SplashActivity extends AppCompatActivity {    public static final String TAG = "SplashActivity";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        int tag = getIntent().getIntExtra("tag", 0);        //1.其他操作 省略        //2.跳主界面        Intent intent = new Intent(this,MainActivity.class);        //tag==1时说明是点击离线通知过来的,需要携带数据跳转        if (tag == 1) {            ExtraBean extraBean= (ExtraBean) getIntent().getSerializableExtra("bean");            intent.putExtra("bean", extraBean);            intent.putExtra("tag", tag);        }        startActivity(intent);    }}
public class MainActivity extends AppCompatActivity {    public static final String TAG = "MainActivity";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        int tag = getIntent().getIntExtra("tag", 0);        if (tag == 1) {//点击通知跳转过来的,有携带数据,需要执行跳转逻辑,根据type跳对应界面            ExtraBean extraBean = (ExtraBean) getIntent().getSerializableExtra("bean");            int type = extraBean.getType();            Log.e(TAG, "umeng  type:" + type);            Intent intent = null;            if (type == 1) {                intent = new Intent(this, DetailActivity.class);            } else {                intent = new Intent(this, ListActivity.class);            }            intent.putExtra("bean", extraBean);            startActivity(intent);        }    }}

DetailActivity、ListActivity代码相同:

public class DetailActivity extends AppCompatActivity {    public static final String TAG = "DetailActivity";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);                ExtraBean extraBean= (ExtraBean) getIntent().getSerializableExtra("bean");        String id = String.valueOf(extraBean.getId());        String title = extraBean.getTitle();        TextView textView = findViewById(R.id.textview);        textView.setText("id:"+id+"\n"+"title:"+title);    }}

按上面的代码执行是没有什么问题的,但是有一种情况时,收到离线通知,不去点击,启动app,再去点击。这时候依然会去执行UmengClickActivity里的onMessage()方法。按照上边的逻辑会启动SplashActivity,而不是根据type值启动对应的Activity。
我的实现思路是,在onMessage()方法内部添加判断,根据结果执行不同逻辑。

public class UmengClickActivity extends UmengNotifyClickActivity {    private static String TAG = UmengClickActivity.class.getName();    @Override    public void onMessage(Intent intent0) {        super.onMessage(intent0);  //此方法必须调用,否则无法统计打开数        String body = intent0.getStringExtra(AgooConstants.MESSAGE_BODY);        Log.e(TAG, "body:" + body);        Gson gson = new Gson();        //将接收到的body信息装换成UmengClickBean        UmengClickBean bean = gson.fromJson(body, UmengClickBean.class);        //ExtraBean包含三个字段:type,id,title,根据type跳转相应界面        ExtraBean extraBean = bean.getExtra();        if (null != bean) {            int type = extraBean.getType();            Intent intent = null;            /**             * 判断栈中是否有MainActivity,有则意味着程序已启动,否则没有             */            if (isExistMainActivity(MainActivity.class)) {                if (type == 1) {                    intent = new Intent(this, DetailActivity.class);                } else {                    intent = new Intent(this, ListActivity.class);                }            } else {                intent = new Intent(this, SplashActivity.class);                intent.putExtra("tag", 1);                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);            }            intent.putExtra("bean", extraBean);            startActivity(intent);            finish();        }    }    @TargetApi(Build.VERSION_CODES.Q)    private boolean isExistMainActivity(Class<?> activity) {        Intent intent = new Intent(this, activity);        ComponentName cmpName = intent.resolveActivity(getPackageManager());        boolean flag = false;        if (cmpName != null) { // 说明系统中存在这个activity                ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);            List taskInfoList =                     am.getRunningTasks(10);            //这里获取的是APP栈的数量,一般也就两个            ActivityManager.RunningTaskInfo runningTaskInfo = taskInfoList.get(0);            // 只是拿当前运行的栈            int numActivities = taskInfoList.get(0).numActivities;            for (ActivityManager.RunningTaskInfo taskInfo : taskInfoList) {                if (taskInfo.baseActivity.equals(cmpName)) {// 说明它已经启动了                    flag = true;                    break;//跳出循环,优化效率                }            }        }        return flag;    }}

2.应用在前台时,接收推送,弹框;在后台时存数据,待应用切到前台时再弹框。
在前台时,在umeng 封装类里的setMessageHandler()方法内部,重写某个方法,我们是重写dealWithNotificationMessage()。
UmengHelper.java

public class UmPushHelper {    public static final String TAG = "UmPushHelper";    static UmPushHelper umPushHelper;    Context context = MyApplacation.getMyApplication();    private PushAgent mPushAgent;    public static UmPushHelper getInstance() {        if (null == umPushHelper) {            umPushHelper = new UmPushHelper();        }        return umPushHelper;    }    /**     * 友盟初始化     * 

* 友盟初始化及相关配置 * 注册 * 通道配置 */ public void init() {// UMConfigure.init(context, "Appkey", "Umeng", UMConfigure.DEVICE_TYPE_PHONE, "Umeng Message Secret"); UMConfigure.setLogEnabled(true);//日志输出,上线关闭 mPushAgent = PushAgent.getInstance(context); mPushAgent.register(new IUmengRegisterCallback() { @Override public void onSuccess(String deviceToken) { //注册成功会返回deviceToken deviceToken是推送消息的唯一标志 Log.i(TAG, "注册成功:deviceToken:--------> " + deviceToken); } @Override public void onFailure(String s, String s1) { Log.e(TAG, "注册失败:--------> " + "s:" + s + ",s1:" + s1); } }); //小米通道 MiPushRegistar.register(context, "xiaomiId", "xiaomiKey"); //华为通道 HuaWeiRegister.register(MyApplacation.getMyApplication()); //魅族通道 MeizuRegister.register(context, "appId", "appKey"); mPushAgent.onAppStart(); //最多展示条数 mPushAgent.setDisplayNotificationNumber(10); //通知或消息接收 setMessageHandler(); //通知点击 setNotificationClickHandler(); } /** * MessageHandler有很多回调方法,根据自己需要选择 */ private void setMessageHandler() { UmengMessageHandler messageHandler = new UmengMessageHandler() { @Override public void dealWithNotificationMessage(Context context, UMessage uMessage) { super.dealWithNotificationMessage(context, uMessage); Log.e(TAG, "um notification msg.extra" + uMessage.extra); try { JSONObject object = new JSONObject(uMessage.extra); int type = object.getInt("type"); Long id = object.getLong("id"); String title = object.getString("title"); ExtraBean bean = new ExtraBean(); bean.setId(id); bean.setType(type); bean.setTitle(title); /** * 应用不在前台时,不弹框,并把推送的数据存起来 * * 在前台时直接弹框 */ if (MyApplacation.getMyApplication().getActivityCount() == 0) { ExtraBeanDao dao = MyApplacation.getMyApplication().getDaoSession().getExtraBeanDao(); dao.insertOrReplace(bean); return; } Intent intent = new Intent(context, NotificationDialogActivity.class); intent.putExtra("bean", bean); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } catch (JSONException e) { e.printStackTrace(); } } }; PushAgent.getInstance(context).setMessageHandler(messageHandler); } private void setNotificationClickHandler() { /** * 自定义行为的回调处理,参考文档:高级功能-通知的展示及提醒-自定义通知打开动作 * UmengNotificationClickHandler是在BroadcastReceiver中被调用,故 * 如果需启动Activity,需添加Intent.FLAG_ACTIVITY_NEW_TASK * */ UmengNotificationClickHandler notificationClickHandler = new UmengNotificationClickHandler() { @Override public void launchApp(Context context, UMessage msg) { Log.e("umenguuu", "helper launchApp extra:" + msg.extra.toString()); super.launchApp(context, msg); } @Override public void openUrl(Context context, UMessage msg) { Log.e("umenguuu", "helper openUrl extra:" + msg.extra.toString()); super.openUrl(context, msg); } @Override public void openActivity(Context context, UMessage msg) { //获取extra字段值 Log.e("umenguuu", "helper openActivity extra:" + msg.extra.toString()); try { JSONObject object = new JSONObject(msg.extra); int type = object.getInt("type"); long id = object.getLong("id"); String title = object.getString("title"); ExtraBean extraBean = new ExtraBean(); extraBean.setId(id); extraBean.setType(type); extraBean.setTitle(title); Intent intent; Log.e("umenguuu", "helper type:" + type); /** * type=1 跳详情界面 * type=2 跳列表界面 */ if (type == 1) { intent = new Intent(context, DetailActivity.class); } else { intent = new Intent(context, ListActivity.class); } intent.putExtra("bean", extraBean); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } catch (JSONException e) { e.printStackTrace(); } } @Override public void dealWithCustomAction(Context context, UMessage msg) { Log.e("umenguuu", "helper dealWithCustomAction extra:" + msg.extra.toString()); } }; //使用自定义的NotificationHandler PushAgent.getInstance(context).setNotificationClickHandler(notificationClickHandler); }}

应用在前台还是在后台的判断是在MyApplication.java内部, mActivityCount==0时,意味着应用在后台。

public class MyApplacation extends Application {    public static final String TAG = "MyApplication";    private static MyApplacation app;    private DaoSession daoSession;    private int mActivityCount = 0;    public static MyApplacation getMyApplication() {        return app;    }    @Override    public void onCreate() {        super.onCreate();        app = this;//        UmPushHelper.getInstance().init();//初始化友盟推送        initDb();//初始化数据库        /**         * 通过mActivityCount判断当前应用在前台还是在后台         */        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {            @Override            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {                Log.d(TAG, "onActivityCreated");            }            @Override            public void onActivityStarted(Activity activity) {                Log.d(TAG, "onActivityStarted");                mActivityCount++;            }            @Override            public void onActivityResumed(Activity activity) {                Log.d(TAG, "onActivityResumed");                /**                 * 后台切前台的时候,判断是否有未弹框的通知消息,如果有遍历弹框                 *                 * 说明:此处设计的是弹框叠加,如果只弹一个框,luanchMode="SingleTop"                 * 并在NotificationDialogActivity内的onNewIntent()方法内处理逻辑                 *                 */                List list = getDaoSession().getExtraBeanDao().queryBuilder().list();                if (null != list && list.size() > 0) {                    for (ExtraBean bean : list) {                        Intent intent = new Intent(activity, NotificationDialogActivity.class);                        intent.putExtra("bean", bean);                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//必须                        activity.startActivity(intent);                    }                    getDaoSession().getExtraBeanDao().deleteAll();                }            }            @Override            public void onActivityPaused(Activity activity) {                Log.d(TAG, "onActivityPaused");            }            @Override            public void onActivityStopped(Activity activity) {                Log.d(TAG, "onActivityStopped");                mActivityCount--;                if (mActivityCount == 0) {//此时切后台                }            }            @Override            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {                Log.d(TAG, "onActivitySaveInstanceState");            }            @Override            public void onActivityDestroyed(Activity activity) {                Log.d(TAG, "onActivityDestroyed");            }        });    }    public int getActivityCount(){        return mActivityCount;    }    public void initDb() {        MyOpenHelper helper = new MyOpenHelper(this, "test.db", null);        //对数据库库加密//        Database db = helper.getEncryptedWritableDb(UUID);        //不加密,uyi        SQLiteDatabase db = helper.getWritableDatabase();        DaoMaster daoMaster = new DaoMaster(db);        daoSession = daoMaster.newSession();    }    public DaoSession getDaoSession() {        return daoSession;    }}

弹框:用一个透明activity实现假弹框,叠加弹框默认lanuchMode即可,只弹一个lanuchMode="singleTop",并重写onNewIntent()方法。

public class NotificationDialogActivity extends AppCompatActivity {    private ExtraBean extraBean;    private TextView textView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.dialog_show_notification);        textView = findViewById(R.id.textview);        TextView tvCancel = findViewById(R.id.tv_cancel);        TextView tvConfirm = findViewById(R.id.tv_confirm);        extraBean = (ExtraBean) getIntent().getSerializableExtra("bean");        textView.setText(extraBean.getTitle());        final int type = extraBean.getType();       tvConfirm.setOnClickListener(new View.OnClickListener() {           @Override           public void onClick(View v) {               Intent intent=null;               if (type == 1) {                   intent = new Intent(NotificationDialogActivity.this, DetailActivity.class);               } else {                   intent = new Intent(NotificationDialogActivity.this, ListActivity.class);               }               intent.putExtra("bean", extraBean);               startActivity(intent);               finish();           }       });       tvCancel.setOnClickListener(new View.OnClickListener() {           @Override           public void onClick(View v) {               finish();           }       });    }    @Override    protected void onNewIntent(Intent intent) {        super.onNewIntent(intent);        extraBean = (ExtraBean) intent.getSerializableExtra("bean");        textView.setText(extraBean.getTitle());    }}

其他类在demo里,demo下载地址:https://github.com/274800562/umengtest.git
如果您觉得此文章对您有帮助,请多多支持。

 

更多相关文章

  1. Android(安卓)中点击两次返回键才退出
  2. ADB 自制万用驱动方法,解决找不到驱动问题,独家秘笈
  3. 【极光推送Jpush】Android集成极光推送及其基本使用
  4. Android(14) ArrayAdapter(数组适配器)的三种方法
  5. 详解Android的服务
  6. Android中实现Native与H5的通信方案汇总
  7. Ubuntu 下不能识别android设备的解决方法
  8. eclipse 上调试android的自带应用方法 一
  9. android中的AdapterView阅读

随机推荐

  1. Android10报错:open failed:EACCES(Permissi
  2. Android(安卓)App Fundamentals
  3. ?android:attr/spinnerDropDownItemStyle
  4. framework——应用进程启动流程
  5. android-Camera.AutoFocusMoveCallback
  6. android 【MeasureSpec】 introduction
  7. 主流开源框架
  8. ObjectAnimator
  9. Android(安卓)OTA升级详细流程分析(non-AB
  10. C++ 关键字