前言
最近在研究Android的音視頻播放暇务,我在Demo中連 Music 的存儲路徑都讀不出來带污,orz...
于是乎,大行百度宛琅,來學(xué)習(xí)一下Android的存儲,研究了各個Android版本下的權(quán)限管理臀晃。參考https://blog.csdn.net/w18756901575/article/details/52085157的讀取圖片示例開始觉渴,來了解一下 Android權(quán)限管理的發(fā)展史。
—— PS:我朋友說我學(xué)習(xí)搞錯了方向徽惋,認(rèn)證反思了一下案淋,的確如此。畢竟自己的主攻方向不在Android的界面開發(fā)上险绘,不能在這個上面花太多時間踢京。
示例源代碼
參考https://blog.csdn.net/w18756901575/article/details/52085157
主要就是 MainActivity.java 和 activity_main.xml
- MainActivity.java
package com.example.demopermission;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import java.io.File;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button mBtnImage;
//調(diào)用系統(tǒng)相冊-選擇圖片
private static final int IMAGE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtnImage = (Button) findViewById(R.id.btnImg);
mBtnImage.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnImg:
/* 簡單查看一下文件*/
File f = new File(Environment.getExternalStorageDirectory() + "/Download");
Log.d("MSG", "absolute path " + f.getAbsolutePath());
Log.d("MSG", "is dir " + f.isDirectory());
Log.d("MSG", "is canRead " + f.canRead());
Log.d("MSG", "is canWrite " + f.canWrite());
if ( f.listFiles() == null) {
Log.d("MSG", "f is null ");
}
else {
Log.d("MSG", "f is not null ");
}
Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, IMAGE);
break;
default:
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case IMAGE:
if (resultCode == Activity.RESULT_OK && data != null) {
Uri selectedImage = data.getData();
String[] filePathColumns = {MediaStore.Images.Media.DATA};
Cursor c = getContentResolver().query(selectedImage, filePathColumns, null, null, null);
c.moveToFirst();
int columnIndex = c.getColumnIndex(filePathColumns[0]);
String imagePath = c.getString(columnIndex);
showImage(imagePath);
c.close();
}
break;
default:
break;
}
}
//加載圖片
private void showImage(String path){
Bitmap bm = BitmapFactory.decodeFile(path);
((ImageView)findViewById(R.id.imgView)).setImageBitmap(bm);
}
}
- activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/btnImg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="點擊選擇圖片"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<ImageView
android:id="@+id/imgView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:scaleType="fitCenter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></ImageView>
</androidx.constraintlayout.widget.ConstraintLayout>
Android 版本 和 權(quán)限管理
加載上面的代碼,會發(fā)現(xiàn)無法提取圖片宦棺,主要是Android限制了你的權(quán)限瓣距。
Android 6.0之前 (API 23 以下)
靜態(tài)配置,僅需要在 AndroidManifest.xml 里進(jìn)行聲明
—— 我自己的環(huán)境 是 minSdkVersion 23 的版本代咸,這種方式肯定沒用
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
Android 10.0 (API 29 以下)
- AndroidManifest.xml 里進(jìn)行聲明
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
- Activity 中動態(tài)聲明
public void requestPermission()
{
String[] permissionList = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
int targetSdkVersion = 0;
try {
final PackageInfo info = this.getPackageManager().getPackageInfo(this.getPackageName(), 0);
targetSdkVersion = info.applicationInfo.targetSdkVersion;//獲取應(yīng)用的Target版本
Log.d("targetSdkVersion: ", String.valueOf(targetSdkVersion));
} catch (PackageManager.NameNotFoundException e) {
Log.e("PackageInfo", "get targetSdkVersion failed.");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//Build.VERSION.SDK_INT是獲取當(dāng)前手機版本 Build.VERSION_CODES.M為6.0系統(tǒng)
//如果系統(tǒng)>=6.0
if (targetSdkVersion >= Build.VERSION_CODES.M) {
//第 1 步: 檢查是否有相應(yīng)的權(quán)限
boolean isAllGranted = checkPermissionAllGranted(permissionList);
if (isAllGranted) {
//Log.e("err","所有權(quán)限已經(jīng)授權(quán)蹈丸!");
return;
}
// 一次請求多個權(quán)限, 如果其他有權(quán)限是已經(jīng)授予的將會自動忽略掉
ActivityCompat.requestPermissions(this, permissionList, 1);
}
}
}
private boolean checkPermissionAllGranted(String[] permissions) {
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
//申請權(quán)限結(jié)果返回處理
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
boolean isAllGranted = true;
// 判斷是否所有的權(quán)限都已經(jīng)授予了
for (int grant : grantResults) {
if (grant != PackageManager.PERMISSION_GRANTED) {
isAllGranted = false;
break;
}
}
if (isAllGranted) {
// 所有的權(quán)限都授予了
Toast.makeText(MainActivity.this, "授權(quán)成功", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "授權(quán)失敗", Toast.LENGTH_LONG).show();
}
}
}
親測有效
Android 10.0 及 以上
這里我就不深究了,不想花時間了呐芥;
主要就是 Android 10.0 對于權(quán)限管理的一些變更 巴拉巴拉的
--- build.gradle 中直接改 targetSdkVersion
不想勞神的辦法
defaultConfig {
applicationId "com.example.demopermission"
minSdkVersion 23
targetSdkVersion 28 ## 直接改
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}