編輯:關於Android編程
提起BroadcastReceiver大家都很熟悉,它和Activity,Service以及ContentProvider並稱為Android的四大組件(四大金剛),可見BroadcastReceiver的重要性,今天我們主要從安全的角度來講解稱為四大組件之一的BroadcastReceiver。可能有的童靴看到這裡會有疑問,BroadcastReceiver有啥好講的,不就是先定義自己的廣播接收器然後在manifest.xml文件中注冊,在需要發送廣播的地方調用Context的sendBroadcast()方法或者是sendOrderBroadcast(),最後在我們自定義的的廣播接收器的onReceive()方法中做相應邏輯麼?恩,這樣使用BroadcastReceiver的總體流程是非常OK的,也說明你對廣播這塊的使用掌握的是非常熟悉的,但今天是從安全的角度來講解BroadcastReveiver的,我相信你閱讀完本文後會有所收獲(*^__^*) ……
BroadcastReceiver的使用很廣泛也很簡單,它的使用可以概括為三步走:
定義自己的BroadcastReceiver並實現onReceive()方法在AndroidManifest.xml中靜態注冊或者在代碼中動態注冊調用Context的sendBroadcast()方法發送廣播這裡先對廣播的兩種注冊方式做一下說明,廣播注冊分為動態注冊和靜態注冊兩種方式。靜態注冊指的是常駐型廣播,無論我們的應用程序在不在運行,只要有符合條件的廣播發來我們的應用程序都可以接受的到,動態注冊指的是只有在我們的應用程序在運行的時候才可以接受到符合條件的廣播。所以當我們要使用廣播時要做一下區分:是用靜態還是用動態。
按照以上步驟我們先定義自己的廣播接收器CustomBroadcastReceiver,定義自己的廣播接收器需要繼承自BroadcastReceiver類,該類是abstract類型的,所以我們需要實現onReceive()方法,代碼如下:
public class CustomBroadcastReceiver extends BroadcastReceiver { public CustomBroadcastReceiver() { } @Override public void onReceive(Context context, Intent intent) { Log.e(this.getClass().getSimpleName(), "current time is :" + System.currentTimeMillis()); } }我們自定義的廣播接收器比較簡單,僅僅在onReceive()方法中打印了一句話而已。接下來我們在AndroidManifest.xml文件中配置CustomBroadcastReceiver,我們讓該Receiver接受指定action的廣播,代碼如下:
好了,在AndroidManifest.xml文件配置完我們的廣播接收器後,我們可以發送一個廣播了。先在布局文件activity_main.xml加入一個可以響應事件的Button,代碼如下:
<framelayout android:background="#aabbcc" android:layout_height="match_parent" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"></framelayout>在布局文件中我們使用了View的onClick屬性(若你對該屬性的用法不太清楚請自行查閱),MainActivity的代碼如下:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void sendBroadcast(View v) { Intent intent = new Intent(MainActivity.this, CustomBroadcastReceiver.class); this.sendBroadcast(intent); } }以上步驟完成之後就可以運行項目了,打開模擬器或者鏈接手機,運行一下,效果如下圖所示:
點擊按鈕,會發現在logcat下有一行日志輸出,如下圖所示:
到這裡我們可以說只是掌握了對廣播的使用,如果在項目中我們也是按照同樣的方式使用了廣播,那麼你的項目可能會存在風險。為什麼這麼說,下面我們來假設一個場景,假如別人反編譯了我們的APK包,看到了我們在配置文件中的這個廣播,那他就可以在自己的應用中也發送一個廣播,因為我們配置的廣播含有intent-filter,所以可以隱式的調起這個廣播,那麼我們的APK會不會做出反應呢?為了做這個測試,我們新建一個工程B(把剛剛的稱為工程A),只要B包名不和A包名相同就行,這樣這倆工程就可以同時跑在一個設備上了,所以在B工程中通過隱式發送廣播的方式,代碼如下:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void sendBroadcast(View v) { Intent intent = new Intent("com.llew.e.customaction"); this.sendBroadcast(intent); } }我們運行運行一下B程序,點擊按鈕,通過查看logcat的輸出,oh,my god,果真工程A中的log打印出來了,如下圖所示:
從logcat的打印結果可以看出,我們通過隱式的發送廣播確實可以讓A工程的廣播接收器做出響應,這樣的APP如果發版了確實是存在安全隱患的,那有沒有解決方式呢?答案是肯定的,我們接下來就看一下3種解決方式:
給廣播接收器添加export屬性在上邊的代碼中我們只是在注冊我們的CustomBroadReceiver的時候添加了export屬性,並把該屬性的值設置為false,難道僅僅就添加一個屬性就OK啦?可能有的童靴還是會產生疑問,為了打消童靴們的疑慮,我們再運行一下代碼,查看一下結果,運行結果如下圖所示:
b)其次給receiver添加permission權限,代碼如下:
c)運行代碼,查看結果如下:
我們通過這樣方式後再分別運行一下程序,分別運行一下,運行結果如下:
定義我們自己的權限時我們給權限使用的級別是normal,如果你對有關權限的級別不是太理解或不屬性,可以去官網查看,這裡不再詳述了,通過查閱官網可知,權限級別有個為signature的,也就是說如果我們在自定義權限的時候把權限級別設置為signature時,只有擁有相同簽名的APP才能調起我們的應用,這就相對的保證了安全,因為我們發版的時候肯定用的是自己的簽名,別人一般情況下是無法獲取到我們的簽名的,所以這種方法是可行的。這時候你肯定心裡樂開了花,真是魔高一尺道高一丈呀,別著急,我們還有另外一種更可靠高效的解決方式,這也是我開發中一直用到的,請繼續往閱讀(*^__^*) ……
public class CustomBroadcastReceiver extends BroadcastReceiver { public static final String LOCAL_CUSTOM_ACTION = "com.llew.seetao.customaction"; public CustomBroadcastReceiver() { } @Override public void onReceive(Context context, Intent intent) { Log.e(this.getClass().getSimpleName(), "current time is :" + System.currentTimeMillis()); } }然後我們看一下在MainActivity中的代碼,如下所示:
public class MainActivity extends Activity { private LocalBroadcastManager mBroadcastManager; private CustomBroadcastReceiver mLocalReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); registerBroadcastReceiver(); } private void registerBroadcastReceiver() { mBroadcastManager = LocalBroadcastManager.getInstance(MainActivity.this); mLocalReceiver = new CustomBroadcastReceiver(); IntentFilter filter = new IntentFilter(CustomBroadcastReceiver.LOCAL_CUSTOM_ACTION); mBroadcastManager.registerReceiver(mLocalReceiver, filter); } public void sendBroadcast(View v) { Intent intent = new Intent(CustomBroadcastReceiver.LOCAL_CUSTOM_ACTION); mBroadcastManager.sendBroadcast(intent); } @Override protected void onDestroy() { super.onDestroy(); if(null != mBroadcastManager) { mBroadcastManager.unregisterReceiver(mLocalReceiver); } } }我們在MainActivity的onCreate()方法中通過LocalBroadcastManger.getInstance()的方式實例化了mBroadcastManager對象,然後通過mBroadcastManager對象調用register()方法來注冊我們的廣播接收器,最後發送廣播的代碼是調用了mBroadcastManger的sendBroadcast()方法,在onDestroy()方法中又調用了mBroadcastManager的unregisterReceiver()方法,我們來運行一下代碼,運行結果如下圖所示:
相信大家對AsyncTask機制都不陌生?基本的使用的方法和注意事項都清楚,編寫一個類,繼承AsyncTask類,必須重寫doInBackground()方法,運行在子線
前言在上一篇Android網絡編程(九)Retrofit2前篇[基本使用]中我們了解了Retrofit的最基本的GET方式訪問網絡的寫法以及請求參數的簡單介紹。這一篇我們
1.打開手機QQ浏覽器,點擊底欄【菜單】 2.向左滑動,選擇【省流加速】 3.看到【廣告過濾】了嗎,點擊進入 4.在這裡即可選擇是否打開【廣告過濾】
前言: Android 4.4之後谷歌提供了沉浸式全屏體驗, 在沉浸式全屏模式下, 狀態欄、 虛擬按鍵動態隱藏, 應用可以使用完整的屏幕空間, 按