最近項目有需求,需要向sd卡寫入文件,在網上找了一大堆文章,很多文章都是吧Internal Storage當成了sd卡,到最後解決辦法都變成了如何動態申請權限了。
在此記錄一下我的解決辦法,在安卓4.4之後,使用android.permission.WRITE_EXTERNAL_STORAGE
權限已經不能向外置sd卡里面寫文件了,申請外置sd卡的權限需要使用google提供的Storage Access Framework,具體使用DocumentFile進行文件的寫入,而不能使用OutputStream寫文件,無論是否有權限,否則會報FileNotFound錯誤。
下面的代碼先申請sd卡的權限,然後在sd卡根目錄寫入一個名爲123.txt文件
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_simpletest);
requestSdCardUriPermission(this, 2);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// real write file to sdcard
if (requestCode == 2 && resultCode == Activity.RESULT_OK) {
Uri uri = data.getData();
DocumentFile documentFile = DocumentFile.fromTreeUri(this, uri);
DocumentFile file = documentFile.createFile("text/plain", "123.txt");
OutputStream outputStream = null;
try {
outputStream = getContentResolver().openOutputStream(file.getUri());
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
outputStreamWriter.write("hahahahahahaha");
outputStreamWriter.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void requestSdCardUriPermission(Activity context, int requestCode) {
Intent intent;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N
&& android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.P) {
intent = createAccessIntent(context);
if (null != intent) {
//安卓Q以下,一般走這條路,彈出的是小型的授權框
context.startActivityForResult(intent, requestCode);
} else {
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
context.startActivityForResult(intent, requestCode);
}
} else {
// 安卓Q必須走這裏,因爲上面的方法會導致授權不成功
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
context.startActivityForResult(intent, requestCode);
}
}
private Intent createAccessIntent(Context context) {
File file = new File(getSDCardName());
StorageManager storageManager =
(StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
StorageVolume volume;
if (null != storageManager) {
volume = storageManager.getStorageVolume(file);
if (null != volume) {
return volume.createAccessIntent(null);
}
}
return null;
}
/**
* get sdcard name
* @return sdcard name
*/
public String getSDCardName() {
StorageManager storageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
List<StorageVolume> storageVolumeList = storageManager.getStorageVolumes();
for (StorageVolume storageVolume : storageVolumeList) {
if (storageVolume.isRemovable()) {
return storageVolume.getUuid();
}
}
}
return null;
}
}
獲取權限由requestSdCardUriPermission
完成,主要是建立一個Intent,然後startActivity去完成sd的授權,在安卓Q版本以下,授權界面是一個小的對話框,在安卓Q上面就是真正跳到另一個界面完成授權,完成授權就會返回到當前Activity的onActivityResult
方法,在此處完成sd卡的文件的寫入。
下一篇文章介紹一種簡化sd卡權限申請的過程;如何優雅的申請sd卡權限