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