如何从 Android 版本 Marshmallow 开始请求从 Android 拨打电话的权限?

Posted

技术标签:

【中文标题】如何从 Android 版本 Marshmallow 开始请求从 Android 拨打电话的权限?【英文标题】:How to ask permission to make phone call from Android from Android version Marshmallow onwards? 【发布时间】:2017-02-28 18:30:56 【问题描述】:

我正在尝试从 android 拨打电话,并且我还设置了运行时权限。它会询问是否允许打电话。但是当我按下允许时,应用程序崩溃了:

我是这样实现的:

private static final int REQUEST_PHONE_CALL = 1;
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + "+918511812660"));

if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
    if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) 
        ActivityCompat.requestPermissions(MainActivity.this, new String[]Manifest.permission.CALL_PHONE,REQUEST_PHONE_CALL);
    
    else
    
        startActivity(intent);
    

else

    startActivity(intent);

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) 
    switch (requestCode) 
        case REQUEST_PHONE_CALL: 
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                startActivity(intent);
            
            else
            

            
            return;
        
    

这是我在 logcat 中得到的:

java.lang.RuntimeException: Failure delivering result ResultInfowho=@android:requestPermissions:, 
     request=1, result=-1, data=Intent  act=android.content.pm.action.REQUEST_PERMISSIONS (has extras)  
     to activity com.devpost.airway/com.devpost.airway.activities.MainActivity: 
     java.lang.NullPointerException: Attempt to invoke virtual method 
     'java.lang.String android.content.Intent.toString()' on a null object reference

      at android.app.ActivityThread.deliverResults(ActivityThread.java:3733)
      at android.app.ActivityThread.handleSendResult(ActivityThread.java:3776)
      at android.app.ActivityThread.-wrap16(ActivityThread.java)
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1412)
      at android.os.Handler.dispatchMessage(Handler.java:102)
      at android.os.Looper.loop(Looper.java:148)
      at android.app.ActivityThread.main(ActivityThread.java:5461)
      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)

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 
    'java.lang.String android.content.Intent.toString()' on a null object reference
      at android.app.Instrumentation.execStartActivity(Instrumentation.java:1485)
      at android.app.Activity.startActivityForResult(Activity.java:3930)
      at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:48)
      at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:75)
      at android.app.Activity.startActivityForResult(Activity.java:3890)
      at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:856)
      at android.app.Activity.startActivity(Activity.java:4213)
      at android.app.Activity.startActivity(Activity.java:4181)
      at com.devpost.airway.activities.MainActivity.onRequestPermissionsResult(MainActivity.java:140)
      at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6582)
      at android.app.Activity.dispatchActivityResult(Activity.java:6460)
      at android.app.ActivityThread.deliverResults(ActivityThread.java:3729)
      at android.app.ActivityThread.handleSendResult(ActivityThread.java:3776) 
      at android.app.ActivityThread.-wrap16(ActivityThread.java) 
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1412) 
      at android.os.Handler.dispatchMessage(Handler.java:102) 
      at android.os.Looper.loop(Looper.java:148) 
      at android.app.ActivityThread.main(ActivityThread.java:5461) 
      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) 

是什么原因造成的?

【问题讨论】:

在 Activity 或 Fragment 中? 你可以检查这个以获得你的答案。 ***.com/a/39646644/6812027 【参考方案1】:

我建议在构造 Intent 呼叫特定号码时使用 ACTION_DIAL 而不是 ACTION_CALL 。使用 ACTION_DIAL ,您的应用程序将不需要呼叫权限,因为 ACTION_DIAL 会打开已输入号码的拨号器,并进一步允许用户决定是实际拨打电话还是在拨打电话之前修改电话号码或根本不拨打电话。

Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + "Your Phone_number"));// Initiates the Intent 
startActivity(intent);

【讨论】:

完美!谢谢【参考方案2】:

堆栈跟踪似乎表明您的权限流程运行正常,但从onRequestPermissionsResult() 调用startActivity 正在崩溃。您传递给startActivityIntent 设置是否正确?我看不到在代码的那部分设置它。

另请注意,ContextCompat.checkSelfPermission 代表您处理 SDK 版本检查,因此您应该可以使用

if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) 
    ActivityCompat.requestPermissions(MainActivity.this, new String[]Manifest.permission.CALL_PHONE,REQUEST_PHONE_CALL);

else

    startActivity(intent);

本身,没有包装 SDK 版本检查代码。

【讨论】:

谢谢,问题是由于 Intent 设置不正确引起的,我赞成这个答案,因为它有助于解决问题。 Hy @OBX 你能解释一下哪个部分的 Intent 设置不正确吗?我有一些问题。谢谢 优秀的答案。这适用于 Android Jelly Bean 4.1。【参考方案3】:

您需要在onRequestPermissionsResult 中创建您的Intent


@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) 
    switch (requestCode) 
        case REQUEST_PHONE_CALL: 
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                    Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + "+918511812660"));
                startActivity(intent);
            
            else
            

            
            return;
        
    
 

【讨论】:

【参考方案4】:

添加新方法

public static boolean hasPermissions(Context context, String... permissions) 
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) 
    for (String permission : permissions) 
        if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) 
            return false;
        
    

return true;

在全局中添加这个

int PERMISSION_ALL = 1; 
String[] PERMISSIONS = Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE;

并在 onCreate 中编写以下代码

if(!hasPermissions(this, PERMISSIONS))
ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);

【讨论】:

【参考方案5】:

将您的onRequestPermissionsResult 更改为以下,您基本上需要先创建intent,然后在授予权限时调用它。那就是你做错了。

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) 
    switch (requestCode) 
        case REQUEST_PHONE_CALL : 
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + "+918511812660"));

                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) 
                    startActivity(intent);
                
            
        
    

【讨论】:

【参考方案6】:
 private void makePhoneCall() 
    String number = items;
    if (number.trim().length() > 0) 
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) 
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]Manifest.permission.CALL_PHONE, REQUEST_CALL);
         else 
            String dial = "tel:" + number;
            startActivity(new Intent(Intent.ACTION_CALL, Uri.parse(dial)));
        
     else 
        Toast.makeText(MainActivity.this, "Enter Phone Number", Toast.LENGTH_SHORT).show();
    

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 
    if (requestCode == REQUEST_CALL) 
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
            makePhoneCall();
         else 
            Toast.makeText(this, "Permission DENIED", Toast.LENGTH_SHORT).show();
        
    

【讨论】:

请提供一些文字来解释此答案有何帮助。解释你做了哪些改变等等。【参考方案7】:

最好不要对该操作使用 phone_call 权限。 Google Play 控制台会提醒您,您应该避免向用户请求不必要的许可。这是一种更好的方法:

/**
 * Make a phone call. Send to the phone app
 *
 * @param phoneNumber the phone number to call
 */
private fun performPhoneCall(phoneNumber: String) 
    val intent = Intent(Intent.ACTION_DIAL)
    intent.data = Uri.parse("tel:$phoneNumber")
    try 
        context.startActivity(intent)
     catch (ex: Exception) 
        displayErrorMessage()
    

【讨论】:

以上是关于如何从 Android 版本 Marshmallow 开始请求从 Android 拨打电话的权限?的主要内容,如果未能解决你的问题,请参考以下文章

android: 如何从 Android Support Lib 版本 4 向 PagerTabStrip 添加图标/drawables?

您如何从 Eclipse 内部制作签名和混淆的 android 版本?

如何对Android的版本进行检测与更新

如何从 android app bundle 分发支持版本?

如何从android API 23和更高版本的操作栏中删除阴影

如何从增加版本号的 Android Studio 中导出 apk