1. 程式人生 > >Notification點選跳轉指定介面(APP被殺死或雙擊退出時喚醒,然後跳轉)

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>

相關推薦

Notification指定介面APP殺死擊退喚醒然後

現有如下需求: 後臺做一個推送,APP收到後以notification的形式展示,使用者點選,跳轉到指定介面。 需求簡單,但是有些細節,確是要在寫的時候,通過大量測試才能知道。 1、如果使用者雙擊退出了,這個時候,APP並沒有被系統殺死,點選手機上的選單鍵

Notification到訊息介面返回到主介面Bug解決

需求: 點選訊息通知欄(Notification),跳轉到APP的訊息介面(MsgActivity),在MsgActivity做一系列操作之後,使用者點選返回鍵,返回到MainActivity 實

android-Notification指定的Activity

今天專案中有這樣的一個需求,當程式還沒被程序“殺死”的時候,後臺推送來了一則訊息,這時候不管是程式在前臺執行,還是後臺中,需要我們以通知欄的方式來通知使用者。 對於通知欄,使用者操作後有兩種情況。 1.當程式在前臺執行的時候,點選後,直接跳到目標Activi

notification並帶資料到具體頁面

public int notify(MPushMessage message, Intent clickIT) { if (message == null || clickIT == null) return -1; Integer nid = messag

iOS開發 指定介面棧中不存在的介面

獲取到導航欄裡的所有控制器: NSMutableArray *viewControllers = [self.navigationController.viewControllers mutableC

圖片放大的效果如果幫助大關注我後期更好的作品奧

第一步,要下載燈箱這個外掛 連線:連結: https://pan.baidu.com/s/1o1mYq5oIfo87YSQF9kjy8w 提取碼: used 下載並且解壓到本地 3.1本地的燈箱解壓如圖 進入src 目錄 如下圖 5.1 專案目錄如下 6.HTM

VS程式設計編輯WPF過程中設計器中介面某一控制元件在XAML中高亮突出顯示相應的控制元件程式碼的設定方法。

在編輯製件WPF過程中,當介面中控制元件較多時,可通過點選設計器中具體的控制元件,從而中在xaml程式碼視窗中快速跳轉到對應的部分。為了突出顯示該部分控制元件程式碼的名稱,方便視覺上直觀的觀察到被選中的控制元件對應的XAML程式碼,可以在VS中設定:選中控制元件後,高亮顯示對應的XAML

react 模擬從後臺獲取選單資料頂部選單切換介面的筆記

 本文是基於Ant design Pro 2.0做的筆記,官方提供的demo(官方demo下載地址),路由是程式配置的,不能滿足專案需求,所以在研究過程中,把所遇到的問題,做一個筆記,最終效果圖如下:   一:需求描述   1 從介面獲取選單,替換預設demo的選單。   &n

做一個小球可以變色和移動使用defineProperty設定get和set

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <st

為什麼layer中彈層內容事件不起作用動態渲染的button無法

  1.click只能為頁面現有的元素繫結點選事件,如果是動態生成的新的元素,是沒有事件的 2.而$(document).on("click","指定的元素",function(){});方法則是將指定的事件繫結在document上,而新產生的元素如果符合指定的元素,那就觸發此事件 &

nginx遮蔽指定介面URL

一、前言 有時候,web平臺上線後,需要遮蔽某個服務介面,但又不想重新上線,可以採用nginx遮蔽指定平臺介面的辦法。 二、具體操作 在nginx的配置檔案nginx.conf檔案的server節點中,新增一個location,示例如下: locat

popupwindow顯示之後返回鍵無反應onKeydown() 和 onBackPressed()方法均未觸發。

最近專案中有一個很小的需求,就是在一個fragment中實現一個彈窗的巢狀功能,說白了也就是倆個 popupwindow 思路很清晰,然後出現一個pop的時候,點選返回鍵ok可以dismiss,然而倆個同時出現的時候,點選返回鍵無效。debug之後發現 按鍵的onKeydown() 和 onBack

收藏、贊按鈕 怎麼由當前的狀態收藏/取消收藏通過設定為取消收藏收藏

看到這裡,我是想介紹我對這個收藏按鈕(五角星),反覆點選來迎合使用者體驗的。那怎麼滿足反覆點選設定狀態呢? 要求是這樣的:我點選收藏按鈕(假設:原先的收藏按鈕是未收藏狀態(暗色)),當我點選過收藏的時候,按鈕被點亮為橙色。當我再次對其點選的時候,當然,我要知道此時的收藏按鈕

RecyclerView 實現瀑布流及事件回撥的介面

RecyclerView 實現瀑布流及點選事件 public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> { private List

手機頁面電話進入撥號介面---a連結的tel屬性

a標籤屬性href中的tel及mailto用處 <a href=”tel:1234567898″>1234567898</a> 指定電話的超連結 <a hre

一篇文章看明白 Android 從應用圖示到介面顯示的過程

Android - Activity 啟動過程 概述 從點選桌面應用圖示到應用顯示的過程我們再熟悉不過了,下面我們來分析下這個過程都做了什麼。 本文主要對以下問題分析: ActivityThread 是什麼,它是一個執行緒嗎,如何被啟動的? Act

Andriod中自定義Dialog樣式的Activity空白處隱藏軟體盤Dialog不消失

一、需求觸發場景: 專案中需要出發帶有EditText的Dialog顯示,要求在編輯完EditText時,點選Dilog的空白處隱藏軟鍵盤。但是Dialog不會消失。示例如下: 二、實現方法: 釋出需求時,我個人曾想過直接通過new的方式直接建立Dialog,經過多次嘗試

(原生js)body隱藏div但若的是指定的位置則不隱藏

<html xmlns="http://www.w3.org/1999/xhtml"><head> <meta http-equiv="Content-Type" co

Android 接收到通知通知欄開啟相應介面

       通知訊息在Android端是一個非常重要的事件,常常會使用到。三方通知也有很多的提供,當然我們也可以自己定義通知欄樣式。來滿足和實現接收到通知並顯示在通知欄上。         現在也不做這些說明,只說明怎麼樣在收到通知後,點選通知欄並開啟相應的介面。當然也是

設定監聽class改變事件由原來的設定單個按鈕觸發方法onclick=“方法”改為addEventListener

原本的在html元素內呼叫方法傳this可替換為jq選擇器選擇對應樣式,然後設定監聽事件: 投訴建議單選 /* function checkThis(e){ var allSpan = document.getElementsByTagN