Quickblox - android 应用程序的 SDK 在应用程序处于后台时无法接听电话

Quickblox -SDK for android App not receive call when app is in background

我正在使用 Quickblox-SDK 为 android 开发视频通话应用程序。如果应用程序打开,应用程序运行良好且完美但如果应用程序在后台,我将无法接听电话。我已经使用此 link 创建了应用程序,请帮忙。 我尝试了以下操作:

1) 当通知到达时打开 CallActivity,使用 GCM 进行通知,但作为接收通知的通话时间,这个东西也不起作用。

谢谢。

创建一个粘性服务,它将 运行 在后台甚至 activity 销毁,该服务负责 QBsession 和所有其他操作,因此它将在后台检测调用。我成功地实现了这一点,并且我通过它成功地在后台接听电话。

public class BloxService extends Service implements QBRTCClientSessionCallbacks {
    private QBChatService chatService;
    private volatile boolean resultReceived = true;
    static final String APP_ID = "";
    static final String AUTH_KEY = "";
    static final String AUTH_SECRET = "";
    static final String ACCOUNT_KEY = "";
    private QBRTCClient rtcClient;
    public static BloxService bloxService;
    private static final String TAG = "BloxService";
    public boolean isSessionRunning;
    public boolean isCallRunning;
    private  Date tokenExpirationDate;
    private QBAuth qbAuth;
    private AppPrefs prefs;

    private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            /*boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
            String reason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
            boolean isFailover = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);*/
            NetworkInfo currentNetworkInfo = (NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
            //NetworkInfo otherNetworkInfo = (NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
            if(currentNetworkInfo!=null && currentNetworkInfo.isConnected()){
                if(!QBChatService.getInstance().isLoggedIn()){
                    if(!isSessionRunning) {
                        initializeQb();
                    }
                }
            }
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
       // prefs = AppPrefs.getInstance(getApplicationContext()); // for testing we put this line on start
        registerReceiver(this.mConnReceiver,
                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("bloxservice","onDestroy");
        try{
            unregisterReceiver(mConnReceiver);
        }catch (Exception e){

        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId){
        prefs = AppPrefs.getInstance(getApplicationContext());
        if (prefs.getData(IS_USER_LOGIN, false)) {
            Log.d("bloxservice","start");
            try {
                if (!QBChatService.getInstance().isLoggedIn()) {
                    initializeQb();
                }
            }catch (Exception e)
            {
                initializeQb();
            }
            bloxService=this;
        }
        else {
            stopSelf();
        }

        return START_STICKY;
    }

    public static BloxService getBloxService() {
        return bloxService;
    }

    public void initializeQb(){
        QBSettings.getInstance().init(getApplicationContext(), APP_ID, AUTH_KEY, AUTH_SECRET);
        QBSettings.getInstance().setAccountKey(ACCOUNT_KEY);
        QBChatService.setDebugEnabled(true);
// added on 20 july
        QBChatService.setDefaultAutoSendPresenceInterval(60);
        QBChatService.ConfigurationBuilder chatServiceConfigurationBuilder = new QBChatService.ConfigurationBuilder();
        chatServiceConfigurationBuilder.setSocketTimeout(60); //Sets chat socket's read timeout in seconds
        chatServiceConfigurationBuilder.setKeepAlive(true); //Sets connection socket's keepAlive option.
        QBChatService.setConfigurationBuilder(chatServiceConfigurationBuilder);
    //    QBChatService.getInstance().startAutoSendPresence(10);// added on 20 july
        chatService = QBChatService.getInstance();

       /* tokenExpirationDate = qbAuth.getTokenExpirationDate();
        try {
          String Token=  QBAuth.getSession().toString();
            QBAuth.createFromExistentToken()
        } catch (QBResponseException e) {
            e.printStackTrace();
        }
*/
        if(AppPrefs.getInstance(this).getData(Constants.PrefsConstatnt.IS_USER_LOGIN,false)){
            Log.e("Login Process", "Started");
            isSessionRunning=true;
            String userId=AppPrefs.getInstance(this).getData(Constants.PrefsConstatnt.USER_ID,"");
            String name=AppPrefs.getInstance(this).getData(Constants.PrefsConstatnt.USER_NAME,"");
            String picUrl=AppPrefs.getInstance(this).getData(Constants.PrefsConstatnt.USER_IMAGE,"");
            String phone=prefs.getData(Constants.PrefsConstatnt.USER_PHONE, "");
            if(name.isEmpty()){
                name=userId;
            }
            createAppSession(Integer.parseInt(userId)<10?"0"+userId:userId,name,userId,picUrl,phone);
        }
    }

    private void createAppSession(final String userId, final String name,final String exId,final String picUrl,final String phone) {
        QBAuth.createSession(new QBEntityCallback<QBSession>() {
            @Override
            public void onSuccess(QBSession qbSession, Bundle bundle) {
                loadUsers(userId, name, exId,picUrl,phone);
                final SharedPreferences prefs = getGCMPreferences(getApplicationContext());
                String registrationId = prefs.getString(PROPERTY_REG_ID, "");
                if (registrationId.isEmpty()) {
                }

                // Subscribe to Push Notifications
                //subscribeToPushNotifications(registrationId);


            }
            @Override
            public void onError(QBResponseException exc) {
                exc.printStackTrace();
                isSessionRunning=false;
            }
        });
    }
    //QBUser users;
    public void loadUsers(String userId,String name,String exId,String picUrl,String phone) {
        final QBUser userr = new QBUser(userId, DataHolder.PASSWORD);
        userr.setFullName(name);
        userr.setExternalId(exId);
        userr.setCustomData(picUrl);
        userr.setPhone(phone);
        QBUsers.signUp(userr, new QBEntityCallback<QBUser>() {
            @Override
            public void onSuccess(QBUser user, Bundle args) {
                createSession(userr.getLogin(), userr.getPassword());

            }

            @Override
            public void onError(QBResponseException error) {
                error.printStackTrace();
                QBUsers.signIn(userr, new QBEntityCallback<QBUser>() {
                    @Override
                    public void onSuccess(QBUser user, Bundle args) {
                        createSession(userr.getLogin(), userr.getPassword());
                    }

                    @Override
                    public void onError(QBResponseException error) {
                        error.printStackTrace();
                        isSessionRunning = false;
                    }
                });
            }
        });
    }
    private void createSession(final String login, final String password) {
        final QBUser user = new QBUser(login, password);
        QBAuth.createSession(login, password, new QBEntityCallback<QBSession>() {
            @Override
            public void onSuccess(QBSession session, Bundle bundle) {
                user.setId(session.getUserId());
                Log.e("User" + session.getUserId(), "Login");
                QBSettings.getInstance().fastConfigInit(APP_ID, AUTH_KEY, AUTH_SECRET);
                sendRegistrationToServer(AppPrefs.getInstance(BloxService.this).getData(Constants.PrefsConstatnt.DEVICE_TOKEN, ""));
                DataHolder.setLoggedUser(user);
                if (chatService.isLoggedIn()) {
                    resultReceived = true;
                    initQBRTCClient();
                    isSessionRunning = false;
                } else {
                    chatService.login(user, new QBEntityCallback<Void>() {
                        @Override
                        public void onSuccess(Void result, Bundle bundle) {
                            initQBRTCClient();
                            resultReceived = true;
                            isSessionRunning = false;
                        }
                        @Override
                        public void onError(QBResponseException exc) {
                            resultReceived = true;
                            isSessionRunning = false;
                        }
                    });
                }

/*                QBRosterListener rosterListener = new QBRosterListener() {
                    @Override
                    public void entriesDeleted(Collection<Integer> userIds) {
                        Log.d("mayanks","changed");
                    }

                    @Override
                    public void entriesAdded(Collection<Integer> userIds) {
                        Log.d("mayanks","changed");
                    }

                    @Override
                    public void entriesUpdated(Collection<Integer> userIds) {
                        Log.d("mayanks","changed");
                    }

                    @Override
                    public void presenceChanged(QBPresence presence) {
                        Log.d("mayanks","changed");
                    }
                };

                QBSubscriptionListener subscriptionListener = new QBSubscriptionListener() {
                    @Override
                    public void subscriptionRequested(int userId) {

                    }
                };

                QBRoster chatRoster = QBChatService.getInstance().getRoster(QBRoster.SubscriptionMode.mutual, subscriptionListener);
                chatRoster.addRosterListener(rosterListener);
                Collection<QBRosterEntry> entries = chatRoster.getEntries();
                QBPresence presence = chatRoster.getPresence(9);
                if (presence!=null) {

                    if (presence.getType() == QBPresence.Type.online) {
                        Log.d("mayanks","online");
                        // User is online
                    }else{
                        Log.d("mayanks","offline");
                        // User is offline
                    }
                }*/

            }

            @Override
            public void onError(QBResponseException exc) {
                resultReceived = true;
                isSessionRunning = false;
            }
        });
    }

    private void sendRegistrationToServer(final String token) {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                final SharedPreferences prefs = getGCMPreferences(getApplicationContext());
                String deviceID = prefs.getString(PROPERTY_DEVICE_ID, null);
                if(deviceID==null)
                {
                    deviceID=DeviceUtils.getDeviceUid();
                    storeDeviceId(getApplicationContext(),deviceID);
                }
                QBSubscription qbSubscription = new QBSubscription();
                qbSubscription.setNotificationChannel(QBNotificationChannel.GCM);
                qbSubscription.setDeviceUdid(deviceID);
                qbSubscription.setRegistrationID(token);
                qbSubscription.setEnvironment(QBEnvironment.DEVELOPMENT); // Don't forget to change QBEnvironment to PRODUCTION when releasing application
                QBPushNotifications.createSubscription(qbSubscription,
                        new QBEntityCallback<ArrayList<QBSubscription>>() {
                            @Override
                            public void onSuccess(ArrayList<QBSubscription> qbSubscriptions, Bundle bundle) {
                                Log.e(TAG, "Successfully subscribed for QB push messages");
                                //saveGcmRegIdToPreferences(gcmRegId);
                                isSessionRunning=false;
                            }

                            @Override
                            public void onError(QBResponseException error) {
                                Log.e(TAG, "Unable to subscribe for QB push messages; " + error.toString());
                                isSessionRunning=false;
                            }
                        });
            }
        });

    }

    @Override
    public void onReceiveNewSession(final QBRTCSession qbrtcSession) {
        Log.d("bloxservice","CallRecive");
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                if(!isCallRunning) {
                    DataHolder.incomingSession = qbrtcSession;
                   /* Map<String,String> userInfo = qbrtcSession.getUserInfo();
                    String s=userInfo.get("mayank");*/
                    Intent intent = new Intent(BloxService.this, CallActivity.class);
                    intent.putExtra("incoming", true);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                }
                else{
                    Log.e("User","Busy");
                }
            }
        });
    }

    @Override
    public void onUserNotAnswer(QBRTCSession qbrtcSession, Integer integer) {
       // ToastUtil.showShortToast(this, "no answer");
    }

    @Override
    public void onCallRejectByUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {
      //  ToastUtil.showShortToast(this,"rejected");
    }

    @Override
    public void onCallAcceptByUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {
        //ToastUtil.showShortToast(this,"accepted");
    }

    @Override
    public void onReceiveHangUpFromUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {

    }

    @Override
    public void onUserNoActions(QBRTCSession qbrtcSession, Integer integer) {
       // ToastUtil.showShortToast(this,"no Action");
    }

    @Override
    public void onSessionClosed(QBRTCSession qbrtcSession) {
       // ToastUtil.showShortToast(this,"onSessionClosed");
    }

    @Override
    public void onSessionStartClose(QBRTCSession qbrtcSession) {
       // ToastUtil.showShortToast(this,"onSessionStartClose");
    }

    private void initQBRTCClient() {
        rtcClient = QBRTCClient.getInstance(this);
        QBVideoChatWebRTCSignalingManager qbChatService = QBChatService.getInstance().getVideoChatWebRTCSignalingManager();
        if (qbChatService != null) {
            qbChatService.addSignalingManagerListener(new QBVideoChatSignalingManagerListener() {
                @Override
                public void signalingCreated(QBSignaling qbSignaling, boolean createdLocally) {
                    if (!createdLocally) {
                        rtcClient.addSignaling((QBWebRTCSignaling) qbSignaling);
                    }
                }
            });
            QBRTCConfig.setMaxOpponentsCount(2);
            QBRTCConfig.setDisconnectTime(40);
            QBRTCConfig.setAnswerTimeInterval(30l);
            QBRTCConfig.setDebugEnabled(true);

            rtcClient.addSessionCallbacksListener(this);
            rtcClient.prepareToProcessCalls();
            QBChatService.getInstance().addConnectionListener(new AbstractConnectionListener() {
                @Override
                public void connectionClosedOnError(Exception e) {

                }
                @Override
                public void reconnectionSuccessful() {

                }
                @Override
                public void reconnectingIn(int seconds) {
                }
            });
        }
    }

    public void logout(){
        chatService.logout(new QBEntityCallback<Void>() {
            @Override
            public void onSuccess(Void result, Bundle bundle) {
            }
            @Override
            public void onError(QBResponseException list) {
            }
        });
    }

/*    public void subscribeToPushNotifications(String registrationID) {
        QBSubscription subscription = new QBSubscription(QBNotificationChannel.GCM);
        subscription.setEnvironment(QBEnvironment.DEVELOPMENT);
        //
        String deviceId;
        final TelephonyManager mTelephony = (TelephonyManager) getSystemService(
                Context.TELEPHONY_SERVICE);
        if (mTelephony.getDeviceId() != null) {
            deviceId = mTelephony.getDeviceId(); /*//*** use for mobiles
        } else {
            deviceId = Settings.Secure.getString(getContentResolver(),
                    Settings.Secure.ANDROID_ID); /*//*** use for tablets
        }
        subscription.setDeviceUdid(deviceId);
        //
        subscription.setRegistrationID(registrationID);
        //
        QBPushNotifications.createSubscription(subscription, new QBEntityCallback<ArrayList<QBSubscription>>() {

            @Override
            public void onSuccess(ArrayList<QBSubscription> subscriptions, Bundle args) {
                Log.d("push_send","sucess");
            }

            @Override
            public void onError(QBResponseException error) {
                Log.d("push_send","sucess");
            }
        });
    }*/
    private SharedPreferences getGCMPreferences(Context context) {
        // This sample app persists the registration ID in shared preferences,
        // but
        // how you store the regID in your app is up to you.
        Log.e("getGCMPreferences", "package= " + context.getPackageName());
        return getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
    }

    private void storeDeviceId(Context context, String deviceId) {
        final SharedPreferences prefs = getGCMPreferences(context);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString(PROPERTY_DEVICE_ID, deviceId);
        editor.commit();
    }

}

终于找到解决办法了。您可以启动 activity onReveiveNewSession 覆盖 CallActivity

的方法
 @Override
public void onReceiveNewSession(final QBRTCSession session) {

    Log.e("PLog", "Session " + session.getSessionID() + " are income");


    Log.d(TAG, "Session " + session.getSessionID() + " are income");
    String curSession = (getCurrentSession() == null) ? null : getCurrentSession().getSessionID();

    if (getCurrentSession() == null) {
        Log.d(TAG, "Start new session");
        initCurrentSession(session);

        setOptionsForSession(session, getDefaultSharedPrefs());
         addIncomeCallFragment(session);

        isInCommingCall = true;
        initIncommingCallTask();
        Intent i = new Intent(CallActivity.this, CallActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        startActivity(i);
    } else {
        Log.d(TAG, "Stop new session. Device now is busy");
        Map<String, String> infoMap = new HashMap<>();
        infoMap.put(Consts.REJECT_REASON, "I'm on a call right now!");
        session.rejectCall(infoMap);
    }

}

我现在已经开始工作了。将以下方法添加到 PushListenerService

class PushListenerService : QBFcmPushListenerService() {

    private val TAG = PushListenerService::class.java.simpleName

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        if (SharedPrefsHelper.hasQbUser()) {
            val qbUser: QBUser = SharedPrefsHelper.getQbUser()
            Log.v(TAG, "App has logged user" + qbUser.id)
            LoginService.start(this, qbUser)
        }
    }

    override fun sendPushMessage(data: MutableMap<Any?, Any?>?, from: String?, message: String?) {
        super.sendPushMessage(data, from, message)
        Log.v(TAG, "From: $from")
        Log.v(TAG, "Message: $message")
        if (SharedPrefsHelper.hasQbUser()) {
            val qbUser: QBUser = SharedPrefsHelper.getQbUser()
            Log.v(TAG, "App has logged user" + qbUser.id)
            LoginService.start(this, qbUser)
        }
    }
}

同时将服务添加到 manifest.xml

<service
    android:name=".quickblox.services.fcm.PushListenerService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

<service
    android:name="com.quickblox.messages.services.fcm.QBFcmPushInstanceIDService">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
    </intent-filter>
</service>

先决条件是 Firebase 推送通知

在 Android

的 quickblox 中获取后台调用的步骤
  1. 已关联您的应用 Firebase。 关注此 link 以获得更多理解 https://docs.quickblox.com/docs/android-push-notifications

  2. 将服务器密钥从 firebase 控制台添加到 quickblox 管理面板,如上所示 link。还要仔细检查 Quickblox 中的环境(开发、生产)。

  3. 在 android 的 Manifest 文件中添加元标记,如 link 所示。

  4. 这是我的PushListenerService代码供参考

    class PushListenerService : QBFcmPushListenerService() {
     private val TAG = PushListenerService::class.java.simpleName
     override fun onNewToken(token: String) {
         super.onNewToken(token)
    
         val tokenRefreshed = true
         SharedPrefs.storeFcmToken(this, token)
         SubscribeService.subscribeToPushes(MyApplication.getInstance(), tokenRefreshed)
    
     }
    
     override fun onMessageReceived(p0: RemoteMessage) {
         Log.d(TAG, "onMessageReceived: $p0")
    
         if (SharedPrefsHelper.hasQbUser()) {
             val qbUser: QBUser? = SharedPrefsHelper.getQbUser()
             if (qbUser != null) {
                 Log.d(TAG, "App has logged user" + qbUser.id)
                 LoginService.start(this, qbUser)
    
             }
         }
     }
    
     override fun sendPushMessage(data: MutableMap<Any?, Any?>?, from: String?, message: String?) {
         super.sendPushMessage(data, from, message)
         Log.v(TAG, "From: $from")
         Log.v(TAG, "Message: $message")
     }
    }
    
  5. 这是 quickblox 示例视频应用 CallActivity.kt 中调用的 sendPushMessage 代码

     fun sendPushMessage(recipients: ArrayList<Int>,
                     senderName: String,
                     newSessionID: String,
                     opponentsIDs: String,
                     opponentsNames: String,
                     isVideoCall: Boolean) {
     val outMessage = String.format(R.string.text_push_notification_message.toString(), senderName)
    
     val currentTime = Calendar.getInstance().time
     val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
     val eventDate = simpleDateFormat.format(currentTime)
    
     // Send Push: create QuickBlox Push Notification Event
     val qbEvent = QBEvent()
     qbEvent.notificationType = QBNotificationType.PUSH
     qbEvent.environment = QBEnvironment.DEVELOPMENT
     // Generic push - will be delivered to all platforms (Android, iOS, WP, Blackberry..)
    
     val json = JSONObject()
     try {
         json.put("message", outMessage)
         json.put("ios_voip", "1")
         json.put("VOIPCall", "1")
         json.put("sessionID", newSessionID)
         json.put("opponentsIDs", opponentsIDs)
         json.put("contactIdentifier", opponentsNames)
         json.put("conferenceType", if (isVideoCall) "1" else "2")
         json.put("timestamp", eventDate)
     } catch (e: JSONException) {
         e.printStackTrace()
     }
    
     qbEvent.message = json.toString()
    
     val userIds = StringifyArrayList(recipients)
     qbEvent.userIds = userIds
    
     QBPushNotifications.createEvents(qbEvent).performAsync(object : QBEntityCallback<List<QBEvent>> {
         override fun onSuccess(p0: List<QBEvent>?, p1: Bundle?) {
             Log.d("FCM", "onSuccess: ")
         }
    
         override fun onError(p0: QBResponseException?) {
             Log.d("FCM", "onError: ${p0?.printStackTrace()}")
         }
     })
    }
    

注意:确保在用户登录时启动 LoginService。在 quickblox 的示例代码中提到了 LoginService