如何在Android Marshmallow及以上版本中请求电话呼叫权限?

24

我正在尝试从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 ResultInfo{who=@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中? - vidulaJ
你可以检查此答案以获取你的答案。http://stackoverflow.com/a/39646644/6812027 - Vishal Puri
7个回答

44

在构建用于拨打特定号码的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
完美!谢谢 - Shujat Munawar
这是最好的答案! - Noor Hossain
它救了我的命 :) - Zeinab Rahnamaee

31

堆栈跟踪似乎表明您的权限流程运行良好,但来自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版本检查的包装。


1
谢谢,问题是因为Intent未正确设置引起的,我会点赞这个答案,因为它帮助解决了问题。 - OBX
嗨@OBX,你能解释一下Intent没有正确设置的部分是哪个吗?我遇到了一些问题。谢谢。 - fanjavaid
1
非常好的答案。这适用于Android Jelly Bean 4.1。 - Val

6
您需要在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;
        }
    }
} 

2

新增方法

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);
}

1

最好不要使用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()
    }
}

0

将您的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);
                }
            }
        }
    }
}

0
 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();
        }
    }
}

请提供一些文本来解释这个答案有多有用。请解释您所做的更改等等。 - darclander

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接