- 近期在友盟上看到许多关于挂断电话导致崩溃的问题,如下异常
java.lang.NoSuchMethodError: No interface method endCall()Z in class Lcom/android/internal/telephony/ITelephony; or its super classes (declaration of 'com.android.internal.telephony.ITelephony' appears in /system/framework/framework.jar!classes3.dex)
at com.lifesense.ble.tools.PhoneCall.stopCall(PhoneCall.java:45)
at com.lifesense.ble.protocol.ProtocolCommand.receivePhoneCommand(ProtocolCommand.java:384)
at com.lifesense.ble.protocol.worker.sync.PedometerWorker$2.onCharacteristicChange(PedometerWorker.java:467)
at com.lifesense.ble.protocol.worker.BaseDeviceWorker.postCharacteristicChange(BaseDeviceWorker.java:1288)
at com.lifesense.ble.system.gatt.BluetoothGattHandler$2.onCharacteristicChanged(BluetoothGattHandler.java:368)
at android.bluetooth.BluetoothGatt$1$8.run(BluetoothGatt.java:478)
at android.bluetooth.BluetoothGatt.runOrQueueCallback(BluetoothGatt.java:780)
at android.bluetooth.BluetoothGatt.access$200(BluetoothGatt.java:41)
at android.bluetooth.BluetoothGatt$1.onNotify(BluetoothGatt.java:472)
at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:306)
at android.os.Binder.execTransactInternal(Binder.java:1021)
at android.os.Binder.execTransact(Binder.java:994)
- 此问题是报此方法不存在,查看手机版本信息发现都发生Android10的设备上,网上很少有关于此问题的描述,在现在的实现中,是根据反射系统API来实现挂断电话,但在API29后Google增加了对反射的限制,在高版本继续使用反射会导致更新未知问题。
- 通过查看资料在高版本上可以TelecomManager来实现挂断电话的需求,此版本在API28及以上才能有效,且需要ANSWER_PHONE_CALLS的权限,在没有权限的情况下会提示SecurityException。
- 可以根据下面代码进行兼容高版本的问题,在API28及以上使用TelecomManager使用endCall方法来挂断电话,API28及以下使用反射来挂断电话
//在项目中建com.android.internal.telephony包,创建ITelephony.aidl文件,以用反射实现挂断电话功能
package com.android.internal.telephony;
interface ITelephony{
boolean endCall();
void answerRingingCall();
}
/**
* 挂断电话 android 9 及以上 可以使用系统api来挂断电话 android 9 及以下 使用反射来挂断电话
* @param context
* @return
*/
public static boolean stopCall(Context context) {
if(context == null) {
return false;
}
if (Build.VERSION.SDK_INT >= 28) { //android 9及以上商用此方式挂断电话
try {
if(context.checkSelfPermission(Manifest.permission.ANSWER_PHONE_CALLS) == PackageManager.PERMISSION_GRANTED) {
TelecomManager manager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
return manager.endCall();
}
} catch (Exception e) {
e.printStackTrace();
}
if(Build.VERSION.SDK_INT > 28) { //android 10 挂断电话使用反射存在NoSuchMethodError问题
return false;
}
}
boolean result = false;
String msg=null;
try
{
ITelephony iTelephony = getITelephony(context);
if(iTelephony==null)
{
msg="failed to hang up,is null";
logMessage(msg,false);
return false;
}
// 结束电话
result = iTelephony.endCall();
if (!result) {
boolean isPermiss = PermissionUtils.checkPermission(context, Manifest.permission.CALL_PHONE);
logMessage("result false isPermiss:" + isPermiss, false);
}
msg="telephony end call results="+result;
logMessage(msg,result);
} catch (Exception e)
{
e.printStackTrace();
String className=null;
if(e.getClass()!=null)
{
className=e.getClass().getName()+e.getMessage();
}
result=PermissionUtils.checkPermission(context, Manifest.permission.CALL_PHONE);
msg="failed to hang up,has exception >>"+className+"("+result+")";
logMessage(msg,false);
return false;
}
return result;
}
private static ITelephony getITelephony(Context context) {
IBinder binder = null;
Method method = null;
ITelephony telephony=null;
try
{
Class> classObj = Class.forName("android.os.ServiceManager");
method = classObj.getMethod("getService", String.class);
binder = (IBinder) method.invoke(null, new Object[] { "phone" });
telephony = ITelephony.Stub.asInterface(binder);
} catch (Exception e1)
{
e1.printStackTrace();
String className=null;
if(e1.getClass()!=null)
{
className=e1.getClass().getName();
}
return null;
}
return telephony;
}