簡述
Android是一個權(quán)限分離的操作系統(tǒng)幔托,每一個應(yīng)用程序運(yùn)行時(shí)都會有一個明確地系統(tǒng)身份標(biāo)識(Linux的user ID和group ID)静暂。部分系統(tǒng)也同樣被特定身份標(biāo)識而隔開。因此,Linux才能將應(yīng)用程序與其他程序和系統(tǒng)隔離開來隐绵。
這樣的機(jī)制可以說是相當(dāng)安全,但是也阻斷了各個應(yīng)用程序之間或者和系統(tǒng)之間的“交流”朴皆。因此贴彼,Android通過一種“permission”機(jī)制強(qiáng)力限制某些特定地操作來達(dá)到細(xì)粒度的安全能力。
進(jìn)程沙箱
Android進(jìn)程沙箱機(jī)制是借鑒Linux中用戶組的原理窍育,其限制了不同應(yīng)用程序之間的資源和數(shù)據(jù)的互訪卡睦。當(dāng)應(yīng)用首次安裝的時(shí),系統(tǒng)會向其分配一個UID漱抓。如果該應(yīng)用程序是第三方的表锻,那么其UID值大于10000,如果是系統(tǒng)應(yīng)用程序則小于10000乞娄。如果應(yīng)用程序卸載后又重新安裝瞬逊,那么其UID值是會改變的。
//獲取應(yīng)用程序UID方法
public void getApplicationUid() {
PackageManager pm = getPackageManager();
try {
ApplicationInfo ai = pm.getApplicationInfo(getPackageName(), PackageManager.GET_ACTIVITIES);
Log.d(getClass().getSimpleName(), "uid = " + ai.uid);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
不同UID的應(yīng)用程序是不能進(jìn)行資源互訪仪或,從而有效達(dá)到進(jìn)程隔離目的确镊。
此外,你可以每個應(yīng)用程序的AndroidManifest.xml文件中使用ShareUserID屬性來使他們擁有同一UserID范删。UserID相同的應(yīng)用程序?qū)幌到y(tǒng)當(dāng)做同一應(yīng)用程序蕾域,擁有相同的UserID和文件權(quán)限。
注意:為了保留系統(tǒng)安全性,只有簽名相同(并且需要相同的shareUserId)的應(yīng)用程序才會被分配相同的UserID旨巷。
一個應(yīng)用程序存儲的任何數(shù)據(jù)都會被分配應(yīng)用程序的UserID,通常是不能被其他應(yīng)用程序所訪問巨缘。當(dāng)使用getSharedPreferences(String, int),openFileOutput(String, int)采呐,或者openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory)若锁,你可以使用MODE_WORLD_READABLE或者M(jìn)ODE_WORLD_WRITEABLE標(biāo)記來允許其他應(yīng)用程序讀或?qū)懳募?/p>
權(quán)限使用
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.app.myapp" >
<uses-permission android:name="android.permission.RECEIVE_SMS" />
...
</manifest>
權(quán)限的使用是相當(dāng)簡單的,某功能需要申請權(quán)限時(shí)懈万,只需在AndroidManifest.xml文件中申明對應(yīng)權(quán)限就行拴清。如上述代碼。
如果你的App在其manifest文件中聲明一系列normal permissions(不會對用戶隱私或者設(shè)備運(yùn)行構(gòu)成威脅的權(quán)限)会通,系統(tǒng)會自動準(zhǔn)許這些權(quán)限申請口予。如果你的App在其manifest文件中聲明一系列dangerous permissions(對用戶隱私或者設(shè)備運(yùn)行構(gòu)成潛在威脅的權(quán)限),系統(tǒng)將會詢問用戶是否同意這些權(quán)限申請涕侈。
詢問的方式根據(jù)系統(tǒng)的版本而有所不同沪停。
1.靜態(tài)權(quán)限申請?jiān)儐柦缑?br>
若設(shè)備運(yùn)行的系統(tǒng)版本為Android5.1(API版本22)或更低,或者App的targetSdkVersion是22或更低裳涛,Android提供的是靜態(tài)權(quán)限申請?jiān)儐柦缑妗?br>
這種詢問方式只要玩過Android手機(jī)的應(yīng)該都見過木张,當(dāng)應(yīng)用程序首次安裝時(shí),會彈出以下類似界面端三,出現(xiàn)在圖標(biāo)列表中的權(quán)限都是dangerous permissions舷礼。
這種詢問方式相當(dāng)霸道,如果想要安裝該應(yīng)用郊闯,我們只有同意其申請的所有權(quán)限妻献。當(dāng)應(yīng)用程序安裝更新時(shí),如果該應(yīng)用程序有新申請的權(quán)限团赁,那么該權(quán)限詢問界面會將新申請的權(quán)限列出育拨。你廢除這些權(quán)限申請的唯一方式就是卸載它們!
-
動態(tài)權(quán)限申請?jiān)儐柦缑?br> 如果設(shè)備運(yùn)行的系統(tǒng)版本為Android6.0(API版本23)或更高欢摄,或者App的targetSdkVersion是23或更高熬丧,Android提供了動態(tài)權(quán)限申請?jiān)儐柦缑妗?br> 其實(shí)這種方式,早在Android6.0之前就有大批國產(chǎn)ROM提供動態(tài)權(quán)限管理方式怀挠,市面上主流的安全軟件也提供這種功能析蝴。Google終于在Android6.0提供了動態(tài)權(quán)限管理功能(不過對我大天朝來說然并卵)。
這種交互方式更加的人性化绿淋,也更加安全嫌变。在應(yīng)用程序運(yùn)行的過程中,如果需要申請網(wǎng)絡(luò)連接權(quán)限躬它,那么系統(tǒng)會彈出權(quán)限詢問對話框供用戶選擇。
當(dāng)然东涡,權(quán)限并不僅僅局限于此冯吓。我們也可以自定義某些權(quán)限來保證安全性倘待。比如,啟動Activity或者Service時(shí)组贺,增加權(quán)限控制凸舵,防止被外部應(yīng)用程序胡亂啟動。
權(quán)限組
對普通第三方應(yīng)用程序來說失尖,權(quán)限一般分為normal permission和dangerous permission啊奄。Android系統(tǒng)所有的dangerous permissions都屬于某一權(quán)限組。如果設(shè)備運(yùn)行的系統(tǒng)版本為Android6.0(API版本23)或更高掀潮,或者App的targetSdkVersion是23或更高菇夸,當(dāng)你的應(yīng)用程序需要一個dangerous permission時(shí),那么:
- 如果應(yīng)用程序在manifest中聲明了一個dangerous permission仪吧,并且它目前沒有該權(quán)限組中的任一權(quán)限择诈,那么系統(tǒng)會彈出一個將要申請權(quán)限組的對話框荷科。但是該對話框不會具體描述是該權(quán)限組中的哪一個權(quán)限。比如應(yīng)用程序需要READ_CONTACTS權(quán)限,那么該對話框僅僅只描述為該應(yīng)用程序需要訪問聯(lián)系人。
2.如果應(yīng)用程序在manifest中聲明了一個dangerous permission,并且它已經(jīng)擁有該權(quán)限組的其他權(quán)限,那么系統(tǒng)將直接允許其訪問該權(quán)限移袍,不與用戶產(chǎn)生交互啡浊。
若設(shè)備運(yùn)行的系統(tǒng)版本為Android5.1(API版本22)或更低涂籽,或者App的targetSdkVersion是22或更低,系統(tǒng)將會在應(yīng)用程序安裝的時(shí)候讓用戶同意權(quán)限申請。系統(tǒng)僅僅只告訴用戶哪些權(quán)限組被申請,而不是單獨(dú)某一個權(quán)限。
Android6.0動態(tài)權(quán)限管理
國產(chǎn)ROM和各類安全軟件早已提供了動態(tài)權(quán)限管理功能诬留,實(shí)現(xiàn)方式上大同小異腺劣,雖然對用戶來說這是相當(dāng)利好的消息涡上,但是對我們開發(fā)者來說,還是很麻煩的腮恩,各種ROM的兼容性讓我們很頭疼武契。終于在棉花糖上,Android提供了動態(tài)權(quán)限管理的相關(guān)API荡含,我們在處理權(quán)限問題上方便了很多咒唆。
當(dāng)你的需要申請一個dangerous permission時(shí)候,你必須在每次申請之前進(jìn)行權(quán)限檢查释液。權(quán)限檢查的方法如下全释。int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE);
如果該方法的返回值為PackageManager.PERMISSION_GRANTED,應(yīng)用程序就可以繼續(xù)后續(xù)操作误债。如果應(yīng)用程序沒有該權(quán)限浸船,那么方法的返回值為PERMISSION_DENIED,并且將會詢問用戶是否允許該權(quán)限寝蹈。
我們在Manifest中申請的任何dangerous permission李命,都會詢問用戶是否允許該權(quán)限,Android提供了幾個申請權(quán)限的方法箫老,調(diào)用之后封字,會彈出一個標(biāo)準(zhǔn)的系統(tǒng)對話框供用戶選擇,該對話框是不能自定義的槽惫。如果一個圖像類軟件申請發(fā)短信權(quán)限周叮,用戶可能會產(chǎn)生懷疑,是不是扣費(fèi)短信界斜。那么我們?nèi)绾谓档陀脩舻牟乱赡胤碌ⅲ緼ndroid提供了一個比較實(shí)用的方法shouldShowRequestPermissionRationale(),該方法給了我們一個解釋的機(jī)會來增加權(quán)限申請通過的概率各薇。如果該權(quán)限之前已被申請過但是被用戶拒絕项贺,那么shouldShowRequestPermissionRationale()方法返回true君躺。
如果你的應(yīng)用程序沒有所需要的權(quán)限,那么你必須要通過調(diào)用requestPermissions()方法來申請權(quán)限开缎,該方法調(diào)用后棕叫,系統(tǒng)會立刻彈出權(quán)限申請?jiān)儐枌υ捒蚬┕┯脩暨x擇,在用戶交互后奕删,系統(tǒng)會立刻通過onRequestPermissionsResult()將結(jié)果返回給應(yīng)用程序俺泣。這里直接將官方文檔中相關(guān)演示代碼貼出來供參考。
// Here, thisActivity is the current activity if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.READ_CONTACTS)) { // Show an expanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an // app-defined int constant. The callback method gets the // result of the request. } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the // contacts-related task you need to do. } else { // permission denied, boo! Disable the // functionality that depends on this permission. } return; } // other 'case' lines to check for other // permissions this app might request } }
再一次完残,系統(tǒng)權(quán)限對話框僅僅只描述你所申請權(quán)限所在權(quán)限組的描述伏钠,而不是針對某一特定權(quán)限。對于同一權(quán)限組的權(quán)限谨设,用戶只需同意一次即可熟掂。這種方案的好壞見仁見智,但是有時(shí)候感覺會把一個很小的問題給擴(kuò)大了扎拣,比如我們只是需要簡單的獲取設(shè)備的IMEI碼赴肚,那么這時(shí)候系統(tǒng)對話框的描述為應(yīng)用程序?qū)⒃L問設(shè)備信息。這時(shí)候用戶肯定會想二蓝,你訪問我設(shè)備信息作甚誉券!然后你的申請被無情拒絕了!
注意:你的應(yīng)用程序需要明確地申請每一個你需要的權(quán)限侣夷,即使用戶已經(jīng)同意了該權(quán)限所在權(quán)限組的另外一個權(quán)限横朋。此外,隨著Android版本的更新百拓,權(quán)限組中所含的權(quán)限可能會改變琴锭。因此,不要偷懶衙传,該顯示申請權(quán)限的地方還是要乖乖申請吧决帖。
合理申請權(quán)限
曾幾何時(shí),權(quán)限的濫用導(dǎo)致用戶隱私泄露頻發(fā)蓖捶,而今地回,用戶對隱私也愈發(fā)敏感,過渡的權(quán)限申請會給用戶造成不良的印象俊鱼。因此刻像,作為有節(jié)操的程序員,我們在權(quán)限申請上應(yīng)該慎重并闲,而不是一股腦把所有權(quán)限都給申請细睡。
隨著Android版本的更新,相應(yīng)的權(quán)限也會更新帝火,因此我們一定要注意不同targetSdkVersion屬性所帶來的權(quán)限變化溜徙,并盡可能的提高targetSdkVersion湃缎。在權(quán)限使用上Google也給了我們一些建議。- 考慮使用Intent來完成權(quán)限相關(guān)的操作
這點(diǎn)建議蠢壹,我覺得可以作為一個比較好的參考嗓违。在Manifest中,我們申請了SEND_SMS權(quán)限图贸,那么可以通過下面代碼完成發(fā)送短信功能蹂季。
SmsManager sm = SmsManager.getDefault(); sm.sendTextMessage(address, null, message, null, null);
如果發(fā)送短信時(shí)候,用戶選擇拒絕該權(quán)限申請疏日,那么你的功能也就Over了乏盐。
如果我們換intent方式進(jìn)行發(fā)送短信,則不會出現(xiàn)權(quán)限被拒絕的情況制恍,代碼如下。Intent intent = new Intent(Intent.ACTION_SENDTO); intent.setData(Uri.parse("smsto:" + number)); intent.putExtra("sms_body", body); context.startActivity(sendIntent);
該方法會跳轉(zhuǎn)到發(fā)送短信界面(如果系統(tǒng)裝有多個短信類應(yīng)用神凑,那么系統(tǒng)會彈出一個選擇應(yīng)用對話框净神,讓用戶選擇使用何種應(yīng)用來完成發(fā)送短信功能),并填充好相應(yīng)的內(nèi)容溉委。類似的鹃唯,撥打電話和使用照相機(jī)等都可以使用intent來完成相應(yīng)的功能,降低了用戶拒絕權(quán)限的風(fēng)險(xiǎn)瓣喊。
最后坡慌,權(quán)限方式和intent方式各有千秋,根據(jù)不同的業(yè)務(wù)情景藻三,我們可以選擇不同的方式洪橘。- 只申請你所需要的權(quán)限
不想讓用戶覺得你的應(yīng)用程序是一個“流氓應(yīng)用”,最好不要過度申請權(quán)限棵帽。
3.不要“吞噬”用戶
在Android6.0中熄求,不要在同一時(shí)刻申請多種權(quán)限。因?yàn)橄到y(tǒng)可能會彈出多個系統(tǒng)權(quán)限詢問對話框逗概,這種情況:
第一弟晚,用戶可能覺得很煩鎖,并退出你的應(yīng)用程序逾苫。
第二卿城,用戶可能由于誤操作,拒絕了你的某些權(quán)限申請铅搓。
因此瑟押,最好的方式還是在你需要的時(shí)候進(jìn)行申請吧。
4.給出你為什么使用權(quán)限的原因
為了降低權(quán)限申請被拒絕的風(fēng)險(xiǎn)狸吞,最好在調(diào)用requestPermissions()之前勉耀,進(jìn)行權(quán)限申請的說明指煎,使用戶覺得你不是在做“壞事”。
動態(tài)權(quán)限申請的一種解決方案
雖然目前Android6.0市場占有率相當(dāng)?shù)捅愠猓请S著時(shí)間的推移至壤,關(guān)于動態(tài)權(quán)限管理這一塊,我們遲早要接觸的枢纠。這里我參考Android官方開發(fā)文檔像街,封裝了動態(tài)權(quán)限管理所需的方法。雖然自己的項(xiàng)目中還未用到動態(tài)權(quán)限管理晋渺,但作為工作之余的學(xué)習(xí)還是大有裨益镰绎!
權(quán)限申請流程
BaseActivity中完成權(quán)限申請
這里我沒有將權(quán)限申請相關(guān)方法封裝成一個類,而是在BaseActivity中添加相關(guān)方法木西。
public class BaseActivity extends AppCompatActivity { //申請請求的request code private final static int YZT_PERMISSION_REQUEST = 12; public final String TAG = getClass().getSimpleName(); //是否跳轉(zhuǎn)過應(yīng)用程序信息詳情頁 private boolean mIsJump2Settings = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override protected void onResume() { super.onResume(); if (mIsJump2Settings) { onRecheckPermission(); mIsJump2Settings = false; } } //單個權(quán)限的檢查 public void checkPermission(@NonNull final String permission, @Nullable String reason) { if (Build.VERSION.SDK_INT < 23) return; int permissionCheck = ContextCompat.checkSelfPermission(this, permission); if (permissionCheck == PackageManager.PERMISSION_GRANTED) { //權(quán)限已經(jīng)申請 onPermissionGranted(permission); } else { if (!TextUtils.isEmpty(reason)) { //判斷用戶先前是否拒絕過該權(quán)限申請畴栖,如果為true,我們可以向用戶解釋為什么使用該權(quán)限 if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) { //這里的dialog可以自定義 new AlertDialog.Builder(this).setCancelable(false).setTitle("溫馨提示").setMessage(reason). setNegativeButton("我知道了", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { requestPermission(new String[]{permission}); dialog.dismiss(); } }).show(); } else { requestPermission(new String[]{permission}); } } else { requestPermission(new String[]{permission}); } } } //多個權(quán)限的檢查 public void checkPermissions(@NonNull String... permissions) { if (Build.VERSION.SDK_INT < 23) return; //用于記錄權(quán)限申請被拒絕的權(quán)限集合 List<String> permissionDeniedList = new ArrayList<>(); for (String permission : permissions) { int permissionCheck = ContextCompat.checkSelfPermission(this, permission); if (permissionCheck == PackageManager.PERMISSION_GRANTED) { onPermissionGranted(permission); } else { permissionDeniedList.add(permission); } } if (!permissionDeniedList.isEmpty()) { String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]); requestPermission(deniedPermissions); } } //調(diào)用系統(tǒng)API完成權(quán)限申請 private void requestPermission(String[] permissions) { ActivityCompat.requestPermissions(this, permissions, YZT_PERMISSION_REQUEST); } //申請權(quán)限被允許的回調(diào) public void onPermissionGranted(String permission) { } //申請權(quán)限被拒絕的回調(diào) public void onPermissionDenied(String permission) { } //申請權(quán)限的失敗的回調(diào) public void onPermissionFailure() { } //如果從設(shè)置界面返回八千,則重新申請權(quán)限 public void onRecheckPermission() { } //彈出系統(tǒng)權(quán)限詢問對話框吗讶,用戶交互后的結(jié)果回調(diào) @Override public final void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case YZT_PERMISSION_REQUEST: if (grantResults.length > 0) { //用于記錄是否有權(quán)限申請被拒絕的標(biāo)記 boolean isDenied = false; for (int i = 0; i < grantResults.length; i++) { if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { onPermissionGranted(permissions[i]); } else { isDenied = true; onPermissionDenied(permissions[i]); } } if (isDenied) { isDenied = false; //如果有權(quán)限申請被拒絕,則彈出對話框提示用戶去修改權(quán)限設(shè)置恋捆。 showPermissionSettingsDialog(); } } else { onPermissionFailure(); } break; } } private void showPermissionSettingsDialog() { new AlertDialog.Builder(this).setCancelable(false).setTitle("溫馨提示"). setMessage("缺少必要權(quán)限\n不然將導(dǎo)致部分功能無法正常使用").setNegativeButton("下次吧", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }).setPositiveButton("去設(shè)置", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { jump2PermissionSettings(); } }).show(); } /** * 跳轉(zhuǎn)到應(yīng)用程序信息詳情頁面 */ private void jump2PermissionSettings() { mIsJump2Settings = true; Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); } }
使用方法
public class MainActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //權(quán)限檢查 String[] permissionArray = {Manifest.permission.SEND_SMS, Manifest.permission.CALL_PHONE}; checkPermissions(permissionArray); // checkPermission(Manifest.permission.SEND_SMS, "YZT將要發(fā)生短信進(jìn)行身份驗(yàn)證"); } @Override public void onRecheckPermission() { super.onRecheckPermission(); String[] permissionArray = {Manifest.permission.SEND_SMS, Manifest.permission.CALL_PHONE}; checkPermissions(permissionArray); } @Override public void onPermissionGranted(String permission) { super.onPermissionGranted(permission); switch (permission) { case Manifest.permission.SEND_SMS: //TODO:發(fā)送短信 Toast.makeText(this, "發(fā)短信咯", Toast.LENGTH_LONG).show(); break; case Manifest.permission.CALL_PHONE: //TODO:打電話 Toast.makeText(this, "電話咯", Toast.LENGTH_LONG).show(); break; } } @Override public void onPermissionDenied(String permission) { super.onPermissionDenied(permission); switch (permission) { case Manifest.permission.SEND_SMS: //TODO: break; case Manifest.permission.CALL_PHONE: //TODO: break; } } @Override public void onPermissionFailure() { super.onPermissionFailure(); Toast.makeText(this, "權(quán)限獲取失敗", Toast.LENGTH_LONG).show(); }
隨著用戶安全意識的提升照皆,我們在權(quán)限的使用上也應(yīng)該更加趨于合理和謹(jǐn)慎。雖然目前Android6.0的占有率很低沸停,但是我們也應(yīng)該未雨綢繆膜毁,盡快引入動態(tài)權(quán)限管理機(jī)制。
最后編輯于 :?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者- 文/潘曉璐 我一進(jìn)店門占业,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绒怨,“玉大人,你說我怎么就攤上這事谦疾∧硝澹” “怎么了?”我有些...
- 文/不壞的土叔 我叫張陵念恍,是天一觀的道長六剥。 經(jīng)常有香客問我晚顷,道長,這世上最難降的妖魔是什么疗疟? 我笑而不...
- 正文 為了忘掉前任该默,我火速辦了婚禮,結(jié)果婚禮上策彤,老公的妹妹穿的比我還像新娘栓袖。我一直安慰自己,他們只是感情好店诗,可當(dāng)我...
- 文/花漫 我一把揭開白布裹刮。 她就那樣靜靜地躺著,像睡著了一般庞瘸。 火紅的嫁衣襯著肌膚如雪捧弃。 梳的紋絲不亂的頭發(fā)上,一...
- 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼底燎!你這毒婦竟也來了刃榨?” 一聲冷哼從身側(cè)響起,我...
- 序言:老撾萬榮一對情侶失蹤双仍,失蹤者是張志新(化名)和其女友劉穎枢希,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體朱沃,經(jīng)...
- 正文 獨(dú)居荒郊野嶺守林人離奇死亡苞轿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
- 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了逗物。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搬卒。...
- 正文 年R本政府宣布坯门,位于F島的核電站微饥,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏古戴。R本人自食惡果不足惜欠橘,卻給世界環(huán)境...
- 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望允瞧。 院中可真熱鬧简软,春花似錦、人聲如沸述暂。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽畦韭。三九已至疼蛾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間艺配,已是汗流浹背察郁。 一陣腳步聲響...
- 正文 我出身青樓,卻偏偏與公主長得像赠法,于是被迫代替她去往敵國和親麦轰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
推薦閱讀更多精彩內(nèi)容
- Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
- 總結(jié)整理了一下android權(quán)限相關(guān)的知識砖织,由于篇幅過長款侵,分為兩篇博客來寫,上篇博客主要是詳解權(quán)限和安全侧纯,下篇主要...
- 剛建了一個QQ群新锈,感興趣的大家一起多多交流:544645972 在 android permission權(quán)限與安全...
- 如果應(yīng)用程序在manifest中聲明了一個dangerous permission仪吧,并且它目前沒有該權(quán)限組中的任一權(quán)限择诈,那么系統(tǒng)會彈出一個將要申請權(quán)限組的對話框荷科。但是該對話框不會具體描述是該權(quán)限組中的哪一個權(quán)限。比如應(yīng)用程序需要READ_CONTACTS權(quán)限,那么該對話框僅僅只描述為該應(yīng)用程序需要訪問聯(lián)系人。