การอนุญาตของ Android ไม่ทำงานแม้ว่าฉันจะประกาศแล้วก็ตาม


167

ฉันกำลังพยายามเขียนรหัสเพื่อส่ง SMS จากแอพ Android แต่เมื่อฉันพยายามส่ง SMS มันจะส่งข้อผิดพลาดกลับมาให้ฉัน:

09-17 18:37:29.974  12847-12847/**.**.****E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: **.**.****, PID: 12847
java.lang.SecurityException: Sending SMS message: uid 10092 does not have android.permission.SEND_SMS.
        at android.os.Parcel.readException(Parcel.java:1599)
        at android.os.Parcel.readException(Parcel.java:1552)
        at com.android.internal.telephony.ISms$Stub$Proxy.sendTextForSubscriber(ISms.java:768)
        at android.telephony.SmsManager.sendTextMessageInternal(SmsManager.java:310)
        at android.telephony.SmsManager.sendTextMessage(SmsManager.java:293)
        at **.**.****.MainActivity$3.onClick(MainActivity.java:70)
        at android.view.View.performClick(View.java:5198)
        at android.view.View$PerformClick.run(View.java:21147)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5417)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

ฉันตรวจสอบแล้ว แต่มีสิทธิ์ในไฟล์ Manifest ดังนี้:

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-feature android:name="android.hardware.telephony"
    android:required="true"/>

<application
    android:exported="true"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:screenOrientation="portrait">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

ฉันค้นหาอินเทอร์เน็ต แต่ข้อผิดพลาดทั้งหมดเกี่ยวกับ<uses-permission/>ไวยากรณ์คุณช่วยฉันทีได้ไหม


คุณกำลังทดสอบกับ Android รุ่นใด
CommonsWare

ฉันกำลังทดสอบกับ android 6.0
Nathan Loudjani

1
แน่นอนมันจะทำงานบน Android รุ่นด้านล่าง มีปรัชญาใหม่ของการอนุญาตใน Android 6.0
Fakher

มีไวยากรณ์พิเศษสำหรับ Android 6 หรือไม่? ฉันจะแน่ใจได้อย่างไรว่ามันใช้งานได้กับเวอร์ชั่นด้านล่าง?
Nathan Loudjani

ก่อนหน้าของฉันtargetsdkversionถูก23อัปเดตเป็น27หลังจากREAD_SMSสิทธิ์การอัปเดตแอปไม่ทำงานซึ่งเปิดใช้งานแล้ว กรุณาช่วย
Sagar

คำตอบ:


237

(ข้อความต่อไปนี้ถูกดึงมาจากบล็อกโพสต์ของฉันเกี่ยวกับเรื่องนี้ )

เหตุผลใหญ่ที่ไม่ได้รับอนุญาตจากคุณในปัจจุบันคือเนื่องจากโครงการของคุณมีtargetSdkVersion23 หรือสูงกว่าและการอนุญาตที่คุณขอเป็น "อันตราย" ใน Android 6.0 รวมถึง:

  • ACCESS_COARSE_LOCATION
  • ACCESS_FINE_LOCATION
  • ADD_VOICEMAIL
  • BODY_SENSORS
  • CALL_PHONE
  • CAMERA
  • GET_ACCOUNTS
  • PROCESS_OUTGOING_CALLS
  • READ_CALENDAR
  • READ_CALL_LOG
  • READ_CELL_BROADCASTS
  • READ_CONTACTS
  • READ_EXTERNAL_STORAGE
  • READ_PHONE_STATE
  • READ_SMS
  • RECEIVE_MMS
  • RECEIVE_SMS
  • RECEIVE_WAP_PUSH
  • RECORD_AUDIO
  • SEND_SMS
  • USE_SIP
  • WRITE_CALENDAR
  • WRITE_CALL_LOG
  • WRITE_CONTACTS
  • WRITE_EXTERNAL_STORAGE

สำหรับสิทธิ์เหล่านี้ไม่เพียง แต่คุณtargetSdkVersionต้องใช้ App 23+ จะมี<uses-permission>องค์ประกอบ (s), แต่คุณยังต้องขอสิทธิ์เหล่านั้นที่รันไทม์จากผู้ใช้บน Android 6.0 ขึ้นไปอุปกรณ์ที่ใช้วิธีการเช่นและcheckSelfPermission() requestPermissions()

เพื่อเป็นการหลีกเลี่ยงปัญหาชั่วคราวให้ลดลงtargetSdkVersionต่ำกว่า 23

อย่างไรก็ตามในที่สุดคุณจะมีเหตุผลบางอย่างที่ต้องการให้คุณ targetSdkVersionอายุ 23 ปีขึ้นไป ในเวลานั้นคุณจะต้องปรับแอพของคุณเพื่อใช้ระบบการอนุญาตรันไทม์ใหม่ เอกสาร Android มี หน้าเฉพาะสำหรับหัวข้อนี้


2
ขอบคุณมากฉันใช้
เมธอด requestPermissions

ตกลงฉันพยายามทำสิ่งนี้มาก่อน แต่ไม่สามารถรับ ContextCompat.checkSelfPermission และ ActivityCompat.requestPermissions ได้พวกเขาให้ข้อผิดพลาด 'ไม่พบ' ในชื่อเมธอด ฉันเดาว่ามันจะทำอย่างไรกับห้องสมุดหายไปก็น่าจะเป็นในแพคเกจ v4 แต่พึ่งพาเพียง gradle compile 'com.android.support:appcompat-v7:22.2.1'ของฉันคือ ฉันควรเปลี่ยนสิ่งนี้เป็น v4 หรือไม่
Ozzy

2
@Ozzy: คุณต้องอยู่ใน v23 รุ่นของไลบรารีสนับสนุน ( 23.x.yสำหรับค่าปัจจุบันของ x และ y) มากกว่า v22 ที่คุณกำลังใช้อยู่ในปัจจุบัน
CommonsWare

ขอบคุณสำหรับอนาคตฉันเดา ตอนนี้ฉันเปลี่ยนเป้าหมายกลับไปเป็น v22 และแม้ว่าที่เก็บข้อมูล SD การ์ดถูกตั้งค่าเป็น 200MB บนเครื่องจำลอง แต่ก็ทำให้ฉันไม่ได้ติดตั้งการ์ด SD แต่ฉันก็เชื่อมต่อโทรศัพท์ของฉันในโหมดนักพัฒนาและทุกอย่างทำงานได้ ด้วยเหตุผลบางอย่างที่จัดเก็บข้อมูลในการ์ด SD ทำงานบนเครื่องจำลองที่เรียกใช้ v23 แต่ไม่ใช่ v22
Ozzy

3
@NathanLoudjani คุณคิดจะแบ่งปันรหัสของคุณที่ใช้สิ่งนี้หรือไม่? ฉันอยู่ในเรือลำเดียวกันและพยายามดิ้นรนใส่สิ่งนี้ในกิจกรรมของฉัน
dschuett

29

เหนือระดับ API 23 คุณจะได้รับโปรแกรมเชิงปฏิบัติเช่น:

    private static final int PERMISSION_REQUEST_CODE = 1;

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {

        if (checkSelfPermission(Manifest.permission.SEND_SMS)
                == PackageManager.PERMISSION_DENIED) {

            Log.d("permission", "permission denied to SEND_SMS - requesting it");
            String[] permissions = {Manifest.permission.SEND_SMS};

            requestPermissions(permissions, PERMISSION_REQUEST_CODE);

        }
    }

7

ขออนุญาตในทางปฏิบัติ (หลัง API 23)

if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.SEND_SMS)
    != PackageManager.PERMISSION_GRANTED) {
    // Permission is not granted 
    // Ask for permision
    ActivityCompat.requestPermissions(this,new String[] { Manifest.permission.SEND_SMS}, 1); 
} 
else {
// Permission has already been granted
}

"หากแอปได้รับอนุญาตวิธีการ checkSelfPermission () จะส่งกลับ PERMISSION_GRANTED และแอปสามารถดำเนินการต่อได้

หากแอปไม่มีสิทธิ์ระบบจะส่งคืน PERMISSION_DENIED และแอปจะต้องขออนุญาตจากผู้ใช้อย่างชัดเจน คุณต้องแจ้งให้ผู้ใช้ทราบเพื่อขออนุญาตดังที่แสดงในรหัสด้านบน การร้องขอ requestPermissions () จะแสดงกล่องโต้ตอบ Android มาตรฐานซึ่งคุณไม่สามารถปรับแต่งได้ "


เราจะวางบรรทัดนี้ที่ไหน ActivityCompat.requestPermissions (นี่คือสตริงใหม่ [] {Manifest.permission.SEND_SMS}, 1); และสิ่งที่ 1 หมายถึงอะไร
LizG


6

เมื่อคุณประกาศpermissonในManifestและก็ไม่ได้หมายถึงการทำงานของคุณมีประสิทธิภาพในงานMarshMallowและMarshMallowคุณได้ตั้ง Permisson RunTimeที่

แบบนี้

ActivityCompat.requestPermissions();

6

โปรดไปที่ลิงค์ด้านล่างนี้ https://developer.android.com/guide/topics/permissions/overview.html

มีตัวอย่างบางตัวอย่างที่นั่นเพื่อเริ่มต้นการอนุญาต

เพื่อให้ Android มีความปลอดภัยมากขึ้นในขณะนี้นักพัฒนาจำเป็นต้องพูดถึงการอนุญาตในรายการและพวกเขาควรจะต้องถามผู้ใช้และในเวลาทำงานเพื่อให้งานเสร็จ พวกเขาได้รับอนุญาตจัดประเภทไว้ในส่วนของการอนุญาตที่เป็นอันตราย

ปฏิทิน

READ_CALENDAR

WRITE_CALENDAR

กล้อง

CAMERA

ติดต่อ

READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS

สถานที่ตั้ง

ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION

ไมโครโฟน

RECORD_AUDIO

โทรศัพท์

READ_PHONE_STATE
READ_PHONE_NUMBERS
CALL_PHONE
ANSWER_PHONE_CALLS (must request at runtime)
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
ANSWER_PHONE_CALLS

SENSORS

BODY_SENSORS

ข้อความ

SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS

การเก็บรักษา

READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

2

ฉันเพิ่มสิ่งนี้ลงใน MainActivity ของฉันเพื่อแก้ไขปัญหาของฉัน

       int MY_PERMISSIONS_REQUEST_READ_CONTACTS=0;
// Here, thisActivity is the current activity
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

                // 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(this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        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.
            }
        }

2

หากคุณใช้ Android เวอร์ชัน "23" หรือ "23+" แอปจะแสดงข้อผิดพลาดเมื่อคุณพยายามเข้าถึงสิ่งที่ต้องได้รับอนุญาตจากผู้ใช้ คุณต้องขออนุญาตในขณะใช้งานแม้ว่าคุณจะประกาศสิทธิ์เหล่านั้นในรายการ Android แล้วก็ตาม

ตรวจสอบสิ่งนี้: https://developer.android.com/training/permissions/requesting.html

แต่ถ้าคุณสร้างแอปพลิเคชันทั้งหมดของคุณและไม่ต้องการเปลี่ยนแปลงในทุกที่การโกงเพียงเล็กน้อยก็เพียงพอแล้ว

ไปที่ไฟล์ "Build.gradle" และเปลี่ยนเวอร์ชั่น Sdk เป้าหมายเป็นน้อยกว่า 23 เช่น 22, 21


1

พร้อมกับคำตอบของ CommonsWare

มีการตั้งค่าความปลอดภัย (ฉันเลือกที่ CM13) เพื่อตั้งค่าขีด จำกัด ข้อความ SMS หากคุณตั้งค่านี้เป็น "ไม่มี" ระบบปฏิบัติการจะป็อปอัพไดอะล็อกสำหรับทุก SMS แม้ว่าจะได้รับสิทธิ์ SMS_SEND ในรันไทม์ สิ่งที่ดีที่สุดคือตั้งให้สูงสุด

หากค่าสูงสุดไม่เพียงพอมีวิธีเพิ่มอัตราสูงสุดบนอุปกรณ์ที่ถูกรูท


0

คุณสามารถใช้รหัสนี้เพื่อเข้าถึงข้อความของคุณ

เปิดกล่องโต้ตอบโดยใช้รหัสด้านล่าง:

ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    1);

รับผลกิจกรรมดังต่อไปนี้:

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case 1: {

          // 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.
                Toast.makeText(MainActivity.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

หรือแก้ไขไฟล์build.gradleและหมายเลขกลุ่มtargetSdkVersionน้อยกว่า23
และไม่จำเป็นต้องใช้รหัสด้านบนอีกต่อไป

หมายเหตุ
แน่นอนว่านี่ไม่ใช่กรณีและเป็นเพียงด้านการศึกษา


0

ดังนั้นฉันจึงต้องสร้างแอปเพื่อส่งและรับข้อความ แต่การดำเนินการส่งล้มเหลวเมื่อใดก็ตามที่ฉันคลิกส่งแม้ว่าจะได้รับอนุญาตก็ตาม ฉันขอสิทธิ์ใช้งานรันไทม์และอนุญาตให้ใช้แล้ว แต่ฉันยังประสบกับข้อผิดพลาดว่ากระบวนการไม่มีสิทธิ์ที่ร้องขอในการส่ง SMS ฉันตรวจสอบการอนุญาตที่ได้รับจาก:

adb shell dumpsys package <package-name>

ลำดับของการร้องขอสิทธิ์ของฉันคือ

  1. RECEIVE_SMS
  2. SEND_SMS

ฉันเปลี่ยนลำดับของการร้องขอและมันทำงานได้ดี สิ่งนี้ได้รับการทดสอบด้วยแอพใหม่ที่สมบูรณ์ (ถอนการติดตั้ง -> ติดตั้ง -> ทดสอบ) คำตอบอาจดูแปลก แต่ก็แค่ให้มันยิง

(ถ้าทำงานตามวิธีที่แสดงในลำดับที่แน่นอนแสดงว่า Android อาจมีข้อบกพร่อง !!)


0

ฉันหวังว่าโซลูชันในการเขียนไปยังที่จัดเก็บข้อมูลภายนอกจะมีประโยชน์เช่นกัน

public  boolean checkPermission() {
        if (Build.VERSION.SDK_INT >= 23) {
            if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED) {
                Timber.tag(LOG_TAG).e("Permission error. You have permission");
                return true;
            } else {
                Timber.tag(LOG_TAG).e("Permission error. You have asked for permission");
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
                return false;
            }
        }
        else { 
            // for a stuff below api level 23
            Timber.tag(LOG_TAG).e("Permission error. You already have the permission");
            return true;
        }
    }

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.