Không thể nhận quyền của WRITE_SETTINGS


85

Khi tôi có API mục tiêu là 23 trên Android M Preview 3, dường như tôi không thể có được quyền Manifest.permission.WRITE_SETTTINGS.

 requestPermissions(new String[]{Manifest.permission.WRITE_SETTINGS},
              101);

Yêu cầu quyền không hiển thị hộp thoại mà tôi mong đợi, nhưng nếu tôi thực hiện cuộc gọi sau mà không có quyền này,

 RingtoneManager.setActualDefaultRingtoneUri(activity, RingtoneManager.TYPE_RINGTONE, ringUri);

Cuộc gọi sẽ ngoại trừ vì tôi không có quyền.

Tôi không chắc sẽ đi đâu từ đây. Có API nhạc chuông mới cho 23 không? Hay sự thay đổi quyền này chỉ khiến bất kỳ ứng dụng không thuộc hệ thống nào không thể thay đổi nhạc chuông?

Câu trả lời:


134

Để sử dụng WRITE_SETTINGS, dựa trên tài liệu:

  1. <uses-permission>phần tử trong tệp kê khai là bình thường.

  2. GọiSettings.System.canWrite() để xem bạn có đủ điều kiện để viết ra cài đặt hay không.

  3. Nếu canWrite()lợi nhuận false, khởi động các ACTION_MANAGE_WRITE_SETTINGShoạt động vì vậy người dùng có thể đồng ý có cho phép ứng dụng của bạn để thực sự viết để cài đặt.

Nói cách khác, ghi vào cài đặt giờ đây là một tham gia hai lần (đồng ý cài đặt, đồng ý riêng trong Cài đặt để cho phép), tương tự như API quản trị thiết bị, dịch vụ trợ năng, v.v.

Cũng xin lưu ý rằng tôi chưa thử sử dụng những thứ này - điều này dựa trên nghiên cứu mà tôi đã thực hiện ngày hôm qua về các thay đổi của Android 6.0 .


Cảm ơn Mark! Làm việc như người ở. developer.android.com/preview/features/runtime-permissions.html cần một số cập nhật nếu chúng tôi sẽ có nhiều cách mới để yêu cầu quyền. (Tôi đã đọc blog của bạn trước khi đăng, nhưng rõ ràng đã không giữ lại phần thông tin đó khi tôi cần)
Justin

Điều này thực sự hiệu quả. Nhưng đối với người dùng cuối, đây là một cách tiếp cận tồi. Bất kỳ dấu hiệu nào cho thấy Google đang thay đổi hành vi này?
Fhl

2
@Fhl: Tôi không biết tại sao họ lại đi theo con đường này thay vì dangerouscách tiếp cận quyền thời gian chạy thông thường mà họ đã áp dụng với những thứ khác trong Android 6.0. Tôi sẽ ngạc nhiên nếu điều này sớm thay đổi.
CommonsWare

2
bạn có thể chỉ định ứng dụng của mình theo ý định như sau:intent.setData(Uri.parse("package:" + Context.getPackageName()));
Olegas Gončarovas.

8
Một điều khác cần lưu ý là dường như có một lỗi trong Android khiến một ứng dụng đã được cài đặt trước đó mà người dùng đã cấp quyền ghi trong hộp thoại được mô tả ở trên, nơi công tắc bật tắt sẽ được đặt ở vị trí đã bật nhưng canWrite trả về false .. Để phương thức canWrite () trả về true, người dùng phải tắt và bật lại công tắc ... Tôi thấy điều này đang được phát triển nhưng hy vọng nó sẽ không phải là thứ mà khách hàng nhìn thấy.
Matt Wolfe

45

Ngoài câu trả lời từ CommonsWare và nhận xét từ Ogix, đây là một số mã giả:

private boolean checkSystemWritePermission() {
    boolean retVal = true;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        retVal = Settings.System.canWrite(this);
        Log.d(TAG, "Can Write Settings: " + retVal);
        if(retVal){
            Toast.makeText(this, "Write allowed :-)", Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(this, "Write not allowed :-(", Toast.LENGTH_LONG).show();
            FragmentManager fm = getFragmentManager();
            PopupWritePermission dialogFragment = new PopupWritePermission();
            dialogFragment.show(fm, getString(R.string.popup_writesettings_title));
        }
    }
    return retVal;
}

Sau đó, Fragment PopupwritePermission đưa ra một cửa sổ giải thích tình huống. Nhấp vào nút OK sẽ mở Menu hệ thống Android nơi có thể cấp Quyền:

private void openAndroidPermissionsMenu() {
    Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
    intent.setData(Uri.parse("package:" + getActivity().getPackageName()));
    startActivity(intent);
}

40

Các câu trả lời trước rất tuyệt, tôi chỉ bổ sung một chút để nhận được kết quả cho việc xin phép.

 public static void youDesirePermissionCode(Activity context){
        boolean permission;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            permission = Settings.System.canWrite(context);
        } else {
            permission = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED;
        }
        if (permission) {
            //do your code
        }  else {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
                intent.setData(Uri.parse("package:" + context.getPackageName()));
                context.startActivityForResult(intent, MainActivity.CODE_WRITE_SETTINGS_PERMISSION);
            } else {
                ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.WRITE_SETTINGS}, MainActivity.CODE_WRITE_SETTINGS_PERMISSION);
            }
        }
    }

Và sau đó trong Activity:

@SuppressLint("NewApi")
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == MainActivity.CODE_WRITE_SETTINGS_PERMISSION && Settings.System.canWrite(this)){
            Log.d("TAG", "MainActivity.CODE_WRITE_SETTINGS_PERMISSION success");
            //do your code
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == MainActivity.CODE_WRITE_SETTINGS_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //do your code
        }
    }

Tôi đặt mã của bạn và nó hoạt động tốt, ngay cả khi được cấp quyền, nhưng nhạc chuông tùy chỉnh vẫn không được chỉ định và vẫn có vấn đề quyền Write_Setting bị từ chối.
Zia Ur Rahman,

4
ActivityCompat.requestPermissions (context, new String [] {Manifest.permission.WRITE_SETTINGS}, ....); không thể được sử dụng. Đó là một sự cho phép đặc biệt. Chúng tôi chỉ có thể yêu cầu quyền này với một mục đích như đã nói trong tài liệu. Ngoài ra trước khi Marshmello phép được cấp permenantly lúc cài đặt thời gian
Anonymous

2
@yshahak biến của bạn là MainActivity.CODE_WRITE_SETTINGS_PERMISSIONgì?
Bruno Bieri

@BrunoBieri vâng bạn nói đúng, tôi đã bỏ qua điều đó. Tôi sẽ chỉnh sửa câu trả lời của mình để nó sẽ dài dòng.
yshahak

Vậy là gì MainActivity.CODE_WRITE_SETTINGS_PERMISSION?
Dấu ngoặc

12

Đây là một ví dụ hoàn chỉnh:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (Settings.System.canWrite(context) {
        // Do stuff here
    }
    else {
        Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
        intent.setData(Uri.parse("package:" + getActivity().getPackageName()));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}

Ý định.setData (Uri.parse ("gói:" + getActivity (). getPackageName ()));
Ole K

7

Đối với Android Marshmellow, bạn yêu cầu sử dụng quyền thời gian chạy nhằm mục đích bảo mật hơn hoặc sử dụng quyền khi cần ở đây là tài liệu

và tài liệu về Cài đặt ghi có ở đây

Trong tệp kê khai, thêm

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

Trong lớp của bạn

private boolean checkSystemWritePermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if(Settings.System.canWrite(context))
            return true;
        else 
            openAndroidPermissionsMenu();
    }
    return false;
}

private void openAndroidPermissionsMenu() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
        intent.setData(Uri.parse("package:" + context.getPackageName()));
        context.startActivity(intent);
    }
}

Và sử dụng nó như thế này

try {
       if (checkSystemWritePermission()) {
            RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, newUri);
            Toast.makeText(context, "Set as ringtoon successfully ", Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(context, "Allow modify system settings ==> ON ", Toast.LENGTH_LONG).show();
            }
        } catch (Exception e) {
            Log.i("ringtoon",e.toString());
            Toast.makeText(context, "unable to set as Ringtoon ", Toast.LENGTH_SHORT).show();
        }

5

Quyền android.permission.WRITE_SETTINGShiện có trong nhóm signature|appop|pre23|preinstallednhư android.permission.CHANGE_NETWORK_STATEandroid.permission.SYSTEM_ALERT_WINDOW

Điều này có nghĩa là bạn nhận được nó trên sdk 22 trở xuống. Trên phiên bản mới hơn, bạn phải là nhà điều hành ứng dụng.


4

Tôi đã sử dụng dưới đây như ..

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        boolean retVal = true;
        retVal = Settings.System.canWrite(this);
        if (retVal == false) {
            if (!Settings.System.canWrite(getApplicationContext())) {

                Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + getPackageName()));
                Toast.makeText(getApplicationContext(), "Please, allow system settings for automatic logout ", Toast.LENGTH_LONG).show();
                startActivityForResult(intent, 200);
            }
        }else {
            Toast.makeText(getApplicationContext(), "You are not allowed to wright ", Toast.LENGTH_LONG).show();
        }
    }

Quyền kê khai

<uses-permission  android:name="android.permission.WRITE_SETTINGS" tools:ignore="ProtectedPermissions" />

2

Đề cập đến quyền bên dưới trong AndroidManifest.xml

Trong Hoạt động, sử dụng bên dưới nếu khác để thay đổi cài đặt.

if(Settings.System.canWrite(this)){
    // change setting here
}
else{
    //Migrate to Setting write permission screen. 
    Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
    intent.setData(Uri.parse("package:" + mContext.getPackageName()));
    startActivity(intent);
}

Vui lòng sử dụng quyền này. <
use-allow

1

Kotlin Version in Simple Steps

Làm theo các bước sau:

1. Thêm phần tử sử dụng của quyền vào manifest.xmlbình thường:

<uses-permission
    android:name="android.permission.WRITE_SETTINGS"
    tools:ignore="ProtectedPermissions" />

2. Nơi bạn muốn thay đổi cài đặt, hãy kiểm tra quyền ghi:

if (context.canWriteSettings) {
    // change the settings here ...
} else {
    startManageWriteSettingsPermission()
}

3. Đồng thời thêm các dòng mã này trong trường hợp yêu cầu quyền:

private fun startManageWriteSettingsPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Intent(
            Settings.ACTION_MANAGE_WRITE_SETTINGS,
            Uri.parse("package:${context.packageName}")
        ).let {
            startActivityForResult(it, REQUEST_CODE_WRITE_SETTINGS_PERMISSION)
        }
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    when (requestCode) {
        REQUEST_CODE_WRITE_SETTINGS_PERMISSION -> {
            if (context.canWriteSettings) {
                // change the settings here ...
            } else {
                Toast.makeText(context, "Write settings permission is not granted!", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

val Context.canWriteSettings: Boolean
    get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.System.canWrite(this)

companion object {
    private const val REQUEST_CODE_WRITE_SETTINGS_PERMISSION = 5
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.