在 onCreateIncomingConnection 中读取 ConnectionService Bundle extras 时出现 ClassNotFoundException com.twilio.voice.CallInvite

问题描述 投票:0回答:1

我正在升级 Flutter 库,以使用与 ConnectionService 集成的 Twilio Voice 进行本机呼叫管理。为了实现这一点,必须扩展

ConnectionService
(从
Service
继承并具有相关的通信方法,即
Intent
s)


背景与背景

要接收来电(通过 FCM 等通知管理器),需要使用

 通知 
ConnectionService

有来电
override fun onCreateIncomingConnection(connectionManagerPhoneAccount: PhoneAccountHandle?, request: ConnectionRequest?): Connection {
    super.onCreateIncomingConnection(connectionManagerPhoneAccount, request)
    Log.d(TAG, "onCreateIncomingConnection")'
    // ... code goes here
    // return new Connection(...)
}

有了这个

onCreateIncomingConnection
,它将要求本机“电话”应用程序显示带有您提供的参数的来电,例如使用 Connection.setAddress

显示来电号码

可以通过使用密钥

TelecomManager.EXTRA_INCOMING_CALL_EXTRAS
(对于来电)将其添加到额外
ConnectionService
,将这些附加信息传递到 Bundle,然后将其添加到新的
Bundle
,例如

来源

private fun handleFCMCallInvite(callInvite: CallInvite, notificationId: Int) {
    // Get telecom manager
    val telecomManager = getSystemService(TELECOM_SERVICE) as TelecomManager

    // Get PhoneAccountHandle
    val caller = callInvite.from!!.toString()
    val componentName = ComponentName(applicationContext.packageName, TwilioVoiceConnectionService::class.java.name)
    val phoneAccountHandle = PhoneAccountHandle(componentName, caller)

    // Create my Bundle containing information e.g. notificationId and callInvite
    val myBundle = Bundle()
    myBundle.putInt(Constants.INCOMING_CALL_NOTIFICATION_ID, notificationId)
    myBundle.putParcelable(Constants.INCOMING_CALL_INVITE, callInvite)

    // Add new incoming call to the telecom manager
    telecomManager.addNewIncomingCall(phoneAccountHandle, Bundle().apply {
        putBundle(EXTRA_INCOMING_CALL_EXTRAS, myBundle)
        putParcelable(EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle)
    })
}

问题

当尝试从

unparcel()
onCreateIncomingConnection
实现中的 Bundled extras 中获取
CallInvite
时,就会出现问题,如下所示: ConnectionService

如上面的代码片段所示,每当使用有效密钥调用 
override fun onCreateIncomingConnection(connectionManagerPhoneAccount: PhoneAccountHandle?, request: ConnectionRequest?): Connection { super.onCreateIncomingConnection(connectionManagerPhoneAccount, request) Log.d(TAG, "onCreateIncomingConnection") val connection: Connection = VoipConnection(applicationContext) connection.extras = request?.extras var ci: CallInvite? = null val myBundle: Bundle? = connection.extras.getBundle(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS); if(myBundle != null) { Log.d(TAG, "onCreateIncomingConnection: myBundle is not null") /// -------------------------------------------------------- /// This next line throws the ClassNotFoundException occurs /// -------------------------------------------------------- if (myBundle.containsKey(Constants.INCOMING_CALL_INVITE) ) { Log.d(TAG, "onCreateIncomingConnection: myBundle contains INCOMING_CALL_INVITE") ci = myBundle.getParcelable(Constants.INCOMING_CALL_INVITE) } else { Log.d(TAG, "onCreateIncomingConnection: myBundle does not contain INCOMING_CALL_INVITE") } } else { Log.d(TAG, "onCreateIncomingConnection: myBundle is null") } ... }

时,我都会绑定一个

CallInvite
对象。 myBundle.containsKey(),包含和访问器按预期工作。

notificationId

包含在捆绑包中时,出现以下异常:

*注:

CallInvite

实现

CallInvite
Parcelable

图书馆等

Class not found when unmarshalling: com.twilio.voice.CallInvite java.lang.ClassNotFoundException: com.twilio.voice.CallInvite at java.lang.Class.classForName(Native Method) at java.lang.Class.forName(Class.java:454) at android.os.Parcel.readParcelableCreator(Parcel.java:3403) at android.os.Parcel.readParcelable(Parcel.java:3337) at android.os.Parcel.readValue(Parcel.java:3239) at android.os.Parcel.readArrayMapInternal(Parcel.java:3636) at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:292) at android.os.BaseBundle.unparcel(BaseBundle.java:236) at android.os.BaseBundle.containsKey(BaseBundle.java:516) at com.twilio.twilio_voice.connectionservice.TwilioVoiceConnectionService.onCreateIncomingConnection(TwilioVoiceConnectionService.kt:43) at android.telecom.ConnectionService.createConnection(ConnectionService.java:2061) at android.telecom.ConnectionService.access$400(ConnectionService.java:96) at android.telecom.ConnectionService$2$1.loggedRun(ConnectionService.java:914) at android.telecom.Logging.Runnable$1.run(Runnable.java:37) at android.telecom.ConnectionService.onAccountsInitialized(ConnectionService.java:3272) at android.telecom.ConnectionService.access$5000(ConnectionService.java:96) at android.telecom.ConnectionService$5$1.loggedRun(ConnectionService.java:2577) at android.telecom.Logging.Runnable$1.run(Runnable.java:37) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8663) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:567) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135) Caused by: java.lang.ClassNotFoundException: com.twilio.voice.CallInvite at java.lang.Class.classForName(Native Method) at java.lang.BootClassLoader.findClass(ClassLoader.java:1358) at java.lang.BootClassLoader.loadClass(ClassLoader.java:1418) at java.lang.ClassLoader.loadClass(ClassLoader.java:312) at java.lang.Class.classForName(Native Method)  at java.lang.Class.forName(Class.java:454)  at android.os.Parcel.readParcelableCreator(Parcel.java:3403)  at android.os.Parcel.readParcelable(Parcel.java:3337)  at android.os.Parcel.readValue(Parcel.java:3239)  at android.os.Parcel.readArrayMapInternal(Parcel.java:3636)  at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:292)  at android.os.BaseBundle.unparcel(BaseBundle.java:236)  at android.os.BaseBundle.containsKey(BaseBundle.java:516)  at com.twilio.twilio_voice.connectionservice.TwilioVoiceConnectionService.onCreateIncomingConnection(TwilioVoiceConnectionService.kt:43)  at android.telecom.ConnectionService.createConnection(ConnectionService.java:2061)  at android.telecom.ConnectionService.access$400(ConnectionService.java:96)  at android.telecom.ConnectionService$2$1.loggedRun(ConnectionService.java:914)  at android.telecom.Logging.Runnable$1.run(Runnable.java:37)  at android.telecom.ConnectionService.onAccountsInitialized(ConnectionService.java:3272)  at android.telecom.ConnectionService.access$5000(ConnectionService.java:96)  at android.telecom.ConnectionService$5$1.loggedRun(ConnectionService.java:2577)  at android.telecom.Logging.Runnable$1.run(Runnable.java:37)  at android.os.Handler.handleCallback(Handler.java:938)  at android.os.Handler.dispatchMessage(Handler.java:99)  at android.os.Looper.loopOnce(Looper.java:226)  at android.os.Looper.loop(Looper.java:313)  at android.app.ActivityThread.main(ActivityThread.java:8663)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:567)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)  Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available

(模块)

build.gradle

更新1

使用最后一个工作解决方案(Java),我决定立即打包和解包以模拟后台发生的情况,似乎这里可能存在问题。

buildscript { ext.kotlin_version = '1.8.0' repositories { google() mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:7.4.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } ... android { compileSdk 33 ... } ... dependencies { ... implementation("com.twilio:voice-android:6.2.1") implementation("com.google.firebase:firebase-messaging-ktx:23.2.1") ... }

Kotlin 也会发生同样的情况,尽管我得到 
public class VoiceFirebaseMessagingService extends FirebaseMessagingService { @Override public void onMessageReceived(final RemoteMessage remoteMessage) { // ... valid message handleInvite(callInvite, notificationId); //... } private void handleInvite(CallInvite callInvite, int notificationId) { Parcel p = Parcel.obtain(); p.writeParcelable(callInvite, 0); ClassLoader classLoader = getApplicationContext().getClassLoader(); CallInvite ci = p.readParcelable(classLoader); // <----------------- ci is always null if(ci != null){ Log.d(TAG, "handleInvite: " + ci.getCallSid()); } else { Log.d(TAG, "handleInvite: null"); } } }

表示

ClassNotFoundException
到目前为止,我已将问题追溯到 

Parcel.readParcelableCreator(@Nullable ClassLoader)

(适用于 Android 11,API 30) CallInvite

public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
        String name = readString();
        if (name == null) {
            return null;
        }
        Parcelable.Creator<?> creator;

始终为 null,因此在调用

name
时返回 null。

Android 11 和 12(API 30、31)上都会出现这种情况

java android twilio twilio-api twilio-programmable-voice
1个回答
0
投票
Twilio Android Quickstart

上详细探讨的一个问题记录了一个 Parcel 问题,并提供了有关问题原因的一些见解。 原因是当前线程的

Parcel.readParcelable

与初始化(加载)语音 SDK 的类加载器不同,正如

ClassLoader
在他的评论
这里
中所建议的那样 SO 的

David Wasser 对此进行了确认和详细讨论。

TL;灾难恢复解决方案

读取包时添加简单的行即可添加要找到的类,即

@afalls-twilio


© www.soinside.com 2019 - 2024. All rights reserved.