java - 在 Android 中使用 sinch 的来电通知,我正在使用 FireBase Messaging 服务,但当应用程序在后台被杀死时没有接到电话

标签 java android firebase firebase-cloud-messaging

我正在开发用于应用间通话的 VoIP 应用。我正在使用 Sinch API、FCM 在后台接收传入消息。它工作正常,但是当应用程序在后台被杀死时,我没有接到来电。

我的代码如下:

FCM-

  public class FireBaseMsgService extends FirebaseMessagingService {
        public static SinchClient sinchClient=null;
        public static CallClient callClient=null;
        String username;

        @Override
        public void onCreate() {
            username=Common.getSavedUserData(this,"user_name");
            super.onCreate();

            if (username != null) {
                initsinch();
            }
        }
    
        @Override
        public void onMessageReceived(RemoteMessage remoteMessage) {
            super.onMessageReceived(remoteMessage);
            //initsinch();

            if (foregrounded()) {
                return;
            }

            if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
    
                initsinch();
                NotificationResult result = sinchClient.relayRemotePushNotificationPayload(remoteMessage.getData());     // relay the background incoming call
            }
        }
    
        // To check if the app is in foreground 
        public static boolean foregrounded() {
            ActivityManager.RunningAppProcessInfo appProcessInfo =
                    new ActivityManager.RunningAppProcessInfo();
            ActivityManager.getMyMemoryState(appProcessInfo);
            return (appProcessInfo.importance == IMPORTANCE_FOREGROUND
                    || appProcessInfo.importance == IMPORTANCE_VISIBLE);
        } 

        private void initsinch() {
            if (sinchClient == null) {
                android.content.Context context = this.getApplicationContext();
                sinchClient = Sinch.getSinchClientBuilder().context(context)
                        .applicationKey(APP_KEY)
                        .applicationSecret(APP_SECRET)
                        .environmentHost(ENVIORNMENT)
                        .userId(username).build();
    
                sinchClient.setSupportCalling(true);
                sinchClient.setSupportActiveConnectionInBackground(true);
                sinchClient.startListeningOnActiveConnection();
                sinchClient.setSupportManagedPush(true);
    
                sinchClient.setPushNotificationDisplayName("my display name");
                sinchClient.addSinchClientListener(new SinchClientListener() {
    
                    public void onClientStarted(SinchClient client) {
                    }

                    public void onClientStopped(SinchClient client) {
                    }

                    public void onClientFailed(SinchClient client, SinchError error) {
                    }

                    public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration registrationCallback) {
                    }

                    public void onLogMessage(int level, String area, String message) {
                    }
                });

                callClient = sinchClient.getCallClient();
                callClient.setRespectNativeCalls(true);
                callClient.addCallClientListener(new CallClientListener() {
                    @Override
                    public void onIncomingCall(CallClient callClient, Call INCOMINGCALL) {
    
    
                        Intent it=new Intent(getApplicationContext(),IncomingCallScreenActivity.class);
                        it.putExtra("mCall", INCOMINGCALL.getCallId());
                        it.putExtra("mCall_caller", INCOMINGCALL.getRemoteUserId());
                        it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(it);
                    }
                });
            }

            if (sinchClient != null && !sinchClient.isStarted()) {
                sinchClient.start();
            }
        }
    }

Username是在Sinch User中初始化的登录用户名。 我在 IncomingCallActivity.call 中创建了 mCall 对象并在 Onservice Connected() 中接收调用对象并调用 sinchCall 监听器,如下所示,

 public class IncomingCallScreenActivity extends BaseActivity {
    static final String TAG=IncomingCallScreenActivity.class.getSimpleName();
    private String mCallId;
    private String mCallLocation;
    private AudioPlayer mAudioPlayer;
    TextView highlight;
   // private NotificationCallvo mCallVo;
    Call fmcall;
    ImageView img;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.incoming);
        highlight=(TextView)findViewById(R.id.highlight);
        Animation a = AnimationUtils.loadAnimation(this, R.anim.blink);
        a.reset();
        highlight.startAnimation(a);
        img=(ImageView)findViewById(R.id.image);
        // Animation shake = AnimationUtils.loadAnimation(this, R.anim.milkshake);
        // img.startAnimation(shake);
        ImageButton answer=(ImageButton)findViewById(R.id.answerButton);
        Animation shake = AnimationUtils.loadAnimation(this, R.anim.milkshake);
        answer.startAnimation(shake);
        answer.setOnClickListener(mClickListener);
        ImageButton decline=(ImageButton) findViewById(R.id.declineButton);
        decline.startAnimation(shake);

        decline.setOnClickListener(mClickListener);

        mAudioPlayer=new AudioPlayer(this);
        mAudioPlayer.playRingTone();

        mCallId=getIntent().getStringExtra(SinchService.CALL_ID);
        System.out.println("cllerid++"+mCallId);
        mCallLocation=getIntent().getStringExtra(SinchService.LOCATION);

    }

    @Override
    protected void onServiceConnected()
    {
        if(getIntent().getExtras().get("mCall")!=null){
            fmcall=FireBaseMsgService.callClient.getCall((String) getIntent().getExtras().get("mCall"));
            ((Call) fmcall).addCallListener(new SinchCallListener());
            TextView remoteUser = (TextView) findViewById(R.id.remoteUser);
            remoteUser.setText(((Call) fmcall).getRemoteUserId());
            // TextView remoteUserLocation = (TextView) findViewById(R.id.remoteUserLocation);
            //   remoteUserLocation.setText("Calling from " + mCallLocation);
        }else {
            Call call = getSinchServiceInterface().getCall(mCallId);

            if (call != null) {

                call.addCallListener(new SinchCallListener());
                TextView remoteUser = (TextView) findViewById(R.id.remoteUser);
                remoteUser.setText(call.getRemoteUserId());
                TextView remoteUserLocation = (TextView) findViewById(R.id.remoteUserLocation);
                remoteUserLocation.setText("Calling from " + mCallLocation);

            } else {
                Log.e(TAG, "Started with invalid callId, aborting");
                finish();
            }

        }


    }

    private void answerClicked() {
        mAudioPlayer.stopRingtone();
        if (getIntent().getExtras().get("mCall") != null) {
            fmcall = FireBaseMsgService.callClient.getCall((String) getIntent().getExtras().get("mCall"));
            fmcall.answer();
            Intent intent = new Intent(this, CallScreenActivity.class);
            intent.putExtra("fcallId", (String) getIntent().getExtras().get("mCall"));
            startActivity(intent);
        } else {
            Call call = getSinchServiceInterface().getCall(mCallId);
            if (call != null) {
                call.answer();
                Intent intent = new Intent(this, CallScreenActivity.class);
                intent.putExtra(SinchService.CALL_ID, mCallId);
                startActivity(intent);
            } else {
                finish();
            }
        }
    }

    private void declineClicked(){
        mAudioPlayer.stopRingtone();
        if(getIntent().getExtras().get("mCall")!=null){
            fmcall.hangup();
        }else {
            Call call=getSinchServiceInterface().getCall(mCallId);
            if(call!=null)
            {
                call.hangup();
            }
            finish();
        }

    }
    private class SinchCallListener implements CallListener {

        @Override
        public void onCallProgressing(Call call) {
            Log.d(TAG,"Call progressing");
        }

        @Override
        public void onCallEstablished(Call call) {
            Log.d(TAG,"Call Established");
        }

        @Override
        public void onCallEnded(Call call) {
            CallEndCause cause=call.getDetails().getEndCause();
            Log.d(TAG, "Call ended, cause: " + cause.toString());
            mAudioPlayer.stopRingtone();
            finish();
        }

        @Override
        public void onShouldSendPushNotification(Call call, List<PushPair> list) {

        }
    }
    private View.OnClickListener mClickListener=new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            switch (view.getId())
            {
                case R.id.answerButton:
                    answerClicked();
                    break;
                case R.id.declineButton:
                    declineClicked();
                    break;
            }
        }
    };
}

当我在后台终止应用程序并调用用户名时 另一台设备,我没有收到来电通知。请帮忙

最佳答案

为此,您需要准备一项服务。以下是服务代码。

public class SinchService extends Service {

private static final String APP_KEY = "REPLACE_WITH_YOUR_APP_KEY";
private static final String APP_SECRET = "REPLACE_WITH_APP_SECRET";
private static final String ENVIRONMENT = "sandbox.sinch.com";

public static final String LOCATION = "LOCATION";
public static final String CALL_ID = "CALL_ID";
static final String TAG = SinchService.class.getSimpleName();

private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient;
private String mUserId;

private StartFailedListener mListener;



@Override
public void onCreate() {
    super.onCreate();
}

@Override
public void onDestroy() {
    if (mSinchClient != null && mSinchClient.isStarted()) {
        mSinchClient.terminate();
    }
    super.onDestroy();
}

private void start(String userName) {
    if (mSinchClient == null) {
        mUserId = userName;
        mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(userName)
                .applicationKey(APP_KEY)
                .applicationSecret(APP_SECRET)
                .environmentHost(ENVIRONMENT).build();

        mSinchClient.setSupportCalling(true);
        mSinchClient.startListeningOnActiveConnection();

        mSinchClient.addSinchClientListener(new MySinchClientListener());
        mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
        mSinchClient.start();
    }
}

private void stop() {
    if (mSinchClient != null) {
        mSinchClient.terminate();
        mSinchClient = null;
    }
}

private boolean isStarted() {
    return (mSinchClient != null && mSinchClient.isStarted());
}

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

public class SinchServiceInterface extends Binder {

    public Call callPhoneNumber(String phoneNumber) {
        return mSinchClient.getCallClient().callPhoneNumber(phoneNumber);
    }

    public Call callUser(String userId) {
        return mSinchClient.getCallClient().callUser(userId);
    }

    public Call callUser(String userId, Map<String, String> headers) {
        return mSinchClient.getCallClient().callUser(userId, headers);
    }

    public String getUserName() {
        return mUserId;
    }

    public boolean isStarted() {
        return SinchService.this.isStarted();
    }

    public void startClient(String userName) {
        start(userName);
    }

    public void stopClient() {
        stop();
    }

    public void setStartListener(StartFailedListener listener) {
        mListener = listener;
    }

    public Call getCall(String callId) {
        return mSinchClient.getCallClient().getCall(callId);
    }

    public NotificationResult relayRemotePushNotificationPayload(final Map payload) {

        if (mSinchClient == null && !mUserId.isEmpty()) {
            start(mUserId);
        } else if (mSinchClient == null && mUserId.isEmpty()) {
            Log.e(TAG, "Can't start a SinchClient as no username is available, unable to relay push.");
            return null;
        }
        return mSinchClient.relayRemotePushNotificationPayload(payload);
    }
}

public interface StartFailedListener {
    void onStartFailed(SinchError error);

    void onStarted();
}

private class MySinchClientListener implements SinchClientListener {

    @Override
    public void onClientFailed(SinchClient client, SinchError error) {
        if (mListener != null) {
            mListener.onStartFailed(error);
        }
        mSinchClient.terminate();
        mSinchClient = null;
    }

    @Override
    public void onClientStarted(SinchClient client) {
        Log.d(TAG, "SinchClient started");
        if (mListener != null) {
            mListener.onStarted();
        }
    }

    @Override
    public void onClientStopped(SinchClient client) {
        Log.d(TAG, "SinchClient stopped");
    }

    @Override
    public void onLogMessage(int level, String area, String message) {
        switch (level) {
            case Log.DEBUG:
                Log.d(area, message);
                break;
            case Log.ERROR:
                Log.e(area, message);
                break;
            case Log.INFO:
                Log.i(area, message);
                break;
            case Log.VERBOSE:
                Log.v(area, message);
                break;
            case Log.WARN:
                Log.w(area, message);
                break;
        }
    }

    @Override
    public void onRegistrationCredentialsRequired(SinchClient client,
            ClientRegistration clientRegistration) {
    }
}

private class SinchCallClientListener implements CallClientListener {

    @Override
    public void onIncomingCall(CallClient callClient, Call call) {
        Log.d(TAG, "Incoming call");
        Intent intent = new Intent(SinchService.this, IncomingCallScreenActivity.class);
        intent.putExtra(CALL_ID, call.getCallId());
        intent.putExtra(LOCATION, call.getHeaders().get("location"));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        SinchService.this.startActivity(intent);
    }
}

在获得用户许可后,在您的主要 Activity 中使用以下代码启动此服务

FirebaseApp.initializeApp(this);
            getApplicationContext().bindService(new Intent(this, SinchService.class), this,
                    BIND_AUTO_CREATE);

并用下面的代码替换你的 FireBaseMsgService

public class FireBaseMsgService extends FirebaseMessagingService {

@Override
public void onMessageReceived(RemoteMessage remoteMessage){
    Map data = remoteMessage.getData();
    if (SinchHelpers.isSinchPushPayload(data)) {
        new ServiceConnection() {
            private Map payload;

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                if (payload != null) {
                    SinchService.SinchServiceInterface sinchService = (SinchService.SinchServiceInterface) service;
                    if (sinchService != null) {
                        NotificationResult result = sinchService.relayRemotePushNotificationPayload(payload);
                        // handle result, e.g. show a notification or similar
                    }
                }
                payload = null;
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {}

            public void relayMessageData(Map<String, String> data) {
                payload = data;
                getApplicationContext().bindService(new Intent(getApplicationContext(), SinchService.class), this, BIND_AUTO_CREATE);
            }
        }.relayMessageData(data);
    }
}

创建临时前台服务

public class TempService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {
    super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        startMyOwnForeground();
    else
        startForeground(1, new Notification());
    return START_STICKY;
}

@RequiresApi(api = Build.VERSION_CODES.O)
private void startMyOwnForeground(){
    String NOTIFICATION_CHANNEL_ID = "com.example.simpleapp";
    String channelName = "My Background Service";
    NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
    chan.setLightColor(Color.BLUE);
    chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    assert manager != null;
    manager.createNotificationChannel(chan);

    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
    Notification notification = notificationBuilder.setOngoing(true)
            .setSmallIcon(R.drawable.ic_launcher_background)
            .setContentTitle("App is running in background")
            .setPriority(NotificationManager.IMPORTANCE_MIN)
            .setCategory(Notification.CATEGORY_SERVICE)
            .build();
    startForeground(2, notification);
}

并在主要 Activity 中启动该服务

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(new Intent(this,TempService.class));
    } else
        startService(new Intent(this,TempService.class));

list 声明部分

   <service
        android:name=".TempService"
        android:exported="true"/>

在你的代码中检查一次你没有下面的代码,如果有请评论它

 getSinchServiceInterface().stopClient();

关于java - 在 Android 中使用 sinch 的来电通知,我正在使用 FireBase Messaging 服务,但当应用程序在后台被杀死时没有接到电话,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55057555/

相关文章:

docker容器中的firebase服务对主机操作系统不可见

java - 从 JpaRepository 方法返回一个 boolean 值

java - gcd 的这种实现是否正确

android - 当 ActionMode 打开时,AppCompat 工具栏保持可见

java - Android如何检查空的edittext

java - 崩溃时如何处理调用?

android - 同步Firebase动态链接?

java - weblogic 10.3.1 上的 jaxws 2.1.5 而不是预安装的 jaxws 2.1.1?

java - 使用 Facebook Graph API 在 Android 应用中获取视频

node.js - 部署错误。构建失败 : Build error details not available. Firebase 云函数