Android 6.0 Write to external SD Card

五迷三道 提交于 2019-12-04 19:16:57

After long hard work I figured out a solution. In Android 6.0 it's not going to give you SD Card path always using this:

System.getenv("SECONDARY_STORAGE") 

or this

Environment.getExternalStorageDirectory()

So I retrieved external SD Card path using this

File[] fs = context.getExternalFilesDirs(null);
            String extPath = "";
            // at index 0 you have the internal storage and at index 1 the real external...
            if (fs != null && fs.length >= 2)
            {
                extPath = fs[1].getAbsolutePath();
                Log.e("SD Path",fs[1].getAbsolutePath());
            }

Rest everything will remain same for permission and all.

Thanks to those who helped me.

From API 23+(6.0) you need to request the read/write permissions even if they are already in your manifest known as Requesting Permissions at Run Time.

from docs

Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app. This approach streamlines the app install process, since the user does not need to grant permissions when they install or update the app. It also gives the user more control over the app's functionality; for example, a user could choose to give a camera app access to the camera but not to the device location. The user can revoke the permissions at any time, by going to the app's Settings screen.

java

// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
};

/**
 * Checks if the app has permission to write to device storage
 *
 * If the app does not has permission then the user will be prompted to grant permissions
 *
 * @param activity
 */
public static void verifyStoragePermissions(Activity activity) {
    // Check if we have write permission
    int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);

    if (permission != PackageManager.PERMISSION_GRANTED) {
        // We don't have permission so prompt the user
        ActivityCompat.requestPermissions(
                activity,
                PERMISSIONS_STORAGE,
                REQUEST_EXTERNAL_STORAGE
        );
    }
}

AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

I think u should check your app permission first, to make sure your storage permission has been turned on.

If there's no storage permission: Please check if u use this permission in your AndroidManifest

<uses-permission android:name="android.permission.STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

If the storage permission has been turned off: Please check your runtime permission, maybe u can refer to this code

private void checkPermissions() {
    if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        return;
    }

    final List<String> permissionsList = new ArrayList<String>();
    permissionsList.add(Manifest.permission.ACCESS_COARSE_LOCATION);
    permissionsList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
    permissionsList.add(Manifest.permission.WRITE_CALENDAR);
    permissionsList.add(Manifest.permission.READ_PHONE_STATE);

    int permissionCheckLocation = ContextCompat.checkSelfPermission(IntroductionActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);
    int permissionCheckStorage = ContextCompat.checkSelfPermission(IntroductionActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    int permissionCheckCalendar = ContextCompat.checkSelfPermission(IntroductionActivity.this, Manifest.permission.WRITE_CALENDAR);
    int permissionCheckPhoneState = ContextCompat.checkSelfPermission(IntroductionActivity.this, Manifest.permission.READ_PHONE_STATE);

    boolean locationPermission=permissionCheckLocation == PackageManager.PERMISSION_GRANTED?true:false;
    boolean storagePermission=permissionCheckStorage == PackageManager.PERMISSION_GRANTED?true:false;
    boolean calendarPermission=permissionCheckCalendar == PackageManager.PERMISSION_GRANTED?true:false;
    boolean phoneStatePermission=permissionCheckPhoneState == PackageManager.PERMISSION_GRANTED?true:false;


    boolean shouldShowLocationPermission=ActivityCompat.shouldShowRequestPermissionRationale(IntroductionActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);
    boolean shouldShowStoragePermission=ActivityCompat.shouldShowRequestPermissionRationale(IntroductionActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    boolean shouldShowCalendarPermission=ActivityCompat.shouldShowRequestPermissionRationale(IntroductionActivity.this, Manifest.permission.WRITE_CALENDAR);
    boolean shouldShowPhoneStatePermission=ActivityCompat.shouldShowRequestPermissionRationale(IntroductionActivity.this, Manifest.permission.READ_PHONE_STATE);

    if (permissionCheckLocation == PackageManager.PERMISSION_GRANTED && permissionCheckStorage == PackageManager.PERMISSION_GRANTED
            && permissionCheckCalendar == PackageManager.PERMISSION_GRANTED && permissionCheckPhoneState == PackageManager.PERMISSION_GRANTED){
        return;
    }else if(((!locationPermission&&!shouldShowLocationPermission)||(!storagePermission&&!shouldShowStoragePermission)
            ||(!calendarPermission&&!shouldShowCalendarPermission)||(!phoneStatePermission&&!shouldShowPhoneStatePermission))&&appContext.localCheckPermission){
        showMessageOKCancel("You need to allow access these permissions",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName()));
                        startActivityForResult(intent, 1);
                    }
                });
    }else{
        ActivityCompat.requestPermissions(IntroductionActivity.this, permissionsList.toArray(new String[permissionsList.size()]), 0);

    }
}

If still have problem, please try to change your file path :

String fileName="mytest5.txt";
 File folder = new File(Environment.getExternalStorageDirectory().getPath() + "/com.gvm.externalstorage.externalstoragetest/");

    if (!folder.exists()) {
        try {
            folder.mkdirs();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Default Save Path Creation Error:" + folder);
        }
    }

    File logFile = new File(folder, fileName);
    if (!logFile.exists()) {
        try {
            logFile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Default Save Path Creation Error:" + logFile);

        }
    }

Best regards. I hope this can help u

@Anvesh Another reliable method i'm using:

/**
 * Get external storage path use reflect on android 6.0 device.
 * Source code:
 * https://github.com/android/platform_frameworks_base/blob/master/core/java/android/os/storage/StorageVolume.java
 *
 * @param removable the sdcard can remove or not, true means external sdcard, false means
 *                  internal sdcard.
 * @return path of sdcard we want
 */
public static String getStoragePath(boolean removable) {
    WinZipApplication application = WinZipApplication.getInstance();
    Context mContext = application.getApplicationContext();
    StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
    Class<?> storageVolumeClazz = null;
    try {
        storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
        Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
        Method getPath = storageVolumeClazz.getMethod("getPath");
        Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
        Object result = getVolumeList.invoke(mStorageManager);
        final int length = Array.getLength(result);
        for (int i = 0; i < length; i++) {
            Object storageVolumeElement = Array.get(result, i);
            String path = (String) getPath.invoke(storageVolumeElement);
            boolean mRemovable = (Boolean) isRemovable.invoke(storageVolumeElement);
            if (removable == mRemovable) {
                return path;
            }
        }
    } catch (Exception e) {
        return null;
    }
    return null;
}

After a lot of research I found ABSOLUTE SOLUTION. IT WORKS.

public boolean checkStorage() {
    File[] fs = con.getExternalFilesDirs(null);
    if (fs.length == 2)
        return true;
    else
        return false;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!