Android 应用程序被终止时无法接收SIP呼叫
即使在应用程序处于后台、退出或重新启动时,我应该如何接收SIP呼叫? 目前,我们正在运行带有粘性通知的前台服务,以保持与sip服务器的连接。这个解决方案不完全有效Android 应用程序被终止时无法接收SIP呼叫,android,android-service,sip,pjsip,Android,Android Service,Sip,Pjsip,即使在应用程序处于后台、退出或重新启动时,我应该如何接收SIP呼叫? 目前,我们正在运行带有粘性通知的前台服务,以保持与sip服务器的连接。这个解决方案不完全有效 请帮助我实现这一点,提前感谢 运行服务是正确的方法。您只需启动该活动即可处理来自该服务的来电。然后,活动可以绑定到您的服务并请求接管呼叫所需的一切。这实际上就是您所需要的。首先,您需要一个永不停止的main服务(即使在设备启动时,在启动接收器的帮助下)。 您必须在MainService而不是MainActivity中初始化sip管理器
请帮助我实现这一点,提前感谢 运行服务是正确的方法。您只需启动该活动即可处理来自该服务的来电。然后,活动可以绑定到您的服务并请求接管呼叫所需的一切。这实际上就是您所需要的。首先,您需要一个永不停止的main服务(即使在设备启动时,在启动接收器的帮助下)。 您必须在MainService而不是MainActivity中初始化sip管理器、sip配置文件和呼叫相关代码 然后,您需要一个接收传入sip呼叫的广播接收器。参见下面的示例 公共类YourReceiver扩展了BroadcastReceiver{
SipAudioCall incomingCall = null;
private static YourReceiver instance;
MainService mainService;
public Intent incomingCallIntent;
public static YourReceiver getInstance() {
return instance;
}
/**
* Processes the incoming call, answers it, and hands it over to the
* MainActivity.
* @param context The context under which the receiver is running.
* @param intent The intent being received.
*/
@Override
public void onReceive(final Context context, Intent intent) {
Log.i(TAG, "onReceive: ");
instance = this;
mainService = MainService.getInstance();
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
@Override
public void onRinging(SipAudioCall call, SipProfile caller) {
Log.i(TAG, "onRinging: ");
}
// extra added
@Override
public void onRingingBack(SipAudioCall call) {
Log.i(TAG, "onRingingBack: ");
super.onRingingBack(call);
}
@Override
public void onReadyToCall(SipAudioCall call) {
Log.i(TAG, "onReadyToCall: ");
super.onReadyToCall(call);
}
@Override
public void onError(SipAudioCall call, int errorCode, String errorMessage) {
Log.e(TAG, "onError: errorCode = " + errorCode + ", errorMessage = " + errorMessage);
super.onError(call, errorCode, errorMessage);
}
@Override
public void onChanged(SipAudioCall call) {
Log.i(TAG, "onChanged: ");
super.onChanged(call);
}
@Override
public void onCalling(SipAudioCall call) {
Log.i(TAG, "onCalling: ");
super.onCalling(call);
}
@Override
public void onCallHeld(SipAudioCall call) {
Log.i(TAG, "onCallHeld: ");
super.onCallHeld(call);
}
@Override
public void onCallBusy(SipAudioCall call) {
Log.i(TAG, "onCallBusy: ");
super.onCallBusy(call);
}
@Override
public void onCallEnded(SipAudioCall call) {
Log.i(TAG, "onCallEnded: ");
}
@Override
public void onCallEstablished(SipAudioCall call) {
Log.i(TAG, "onCallEstablished: ");
super.onCallEstablished(call);
}
};
mainService = MainService.getInstance();
incomingCall = mainService.manager.takeAudioCall(intent,listener);
if(mainService.manager.isIncomingCallIntent(intent)){
incomingCallIntent = intent;
}
//starting call screen activity when the receiver receives incoming call
Intent i = new Intent(context, CallActivity.class);
i.putExtra("name", peerName);
i.putExtra("number", peerNumber);
i.putExtra("callType", "Incoming");
context.startActivity(i);
//接收方收到的Sip呼叫被分配给MainService.call,以便MainService可以执行进一步的处理
mainService.call = incomingCall;
} catch (Exception e) {
if (incomingCall != null) {
incomingCall.close();
}
}
}
}要使服务连续运行,请启动作业调度程序,使此作业成为android系统作业的一部分
package com.xxx;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import androidx.annotation.RequiresApi;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class XXJobService extends JobService {
private String TAG = "XXJobService";
private Context context;
public XXJobService() {
}
@Override
public boolean onStartJob(JobParameters params) {
context = this;
try {
if (!MyApp.isServiceRunning(context, MainService.class.getName())) {
Log.i(TAG, "onStartJob : MainService not running so start");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.getApplicationContext()
.startForegroundService(new Intent(context, MainService.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
} else {
context.getApplicationContext()
.startService(new Intent(context, MainService.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
}
}
} catch (Exception e) {
Log.e(TAG, "Exception - MainService not running: " + e.getLocalizedMessage());
}
Log.i(TAG, "onStartJob, returnValue = " + returnValue);
return returnValue;
}
@Override
public boolean onStopJob(JobParameters params) {
boolean returnValue = true;
Log.i(TAG, "onStopJob, returnValue = " + returnValue);
return returnValue;
}
}
在项目中创建一个扩展应用程序的应用程序类,并在清单中定义它
import android.app.ActivityManager;
import android.app.Application;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import java.util.Arrays;
import java.util.List;
public class MyApp extends Application {
Context context;
private static MyApp instance;
static String TAG = "MyApp";
MainService mainService;
JobScheduler jobScheduler;
private static final int JOB_ID = 1;
public static MyApp getInstance() {
return instance;
}
@Override
public void onCreate() {
super.onCreate();
context = this;
instance = this;
Log.i(TAG, "onCreate: ");
// Job scheduler for android version Lolipop(Android 5.0) and above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
ComponentName jobService = new ComponentName(getPackageName(), XXJobService.class.getName());
Log.e(TAG, "onCreate: ComponentName : " + jobService );
JobInfo jobInfo = new JobInfo.Builder(JOB_ID, jobService)
.setPersisted(true)
.setPeriodic(5000)
.build();
int jobId = jobScheduler.schedule(jobInfo);
if (jobId == JobScheduler.RESULT_SUCCESS) {
Log.e(TAG, "JobScheduler RESULT_SUCCESS");
// Toast.makeText(context, "Successfully scheduled job : " + jobId, Toast.LENGTH_SHORT).show();
} else {
Log.e(TAG, "JobScheduler RESULT_FAILURE: " + jobId);
// Toast.makeText(context, "RESULT_FAILURE: " + jobId, Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e(TAG, "JobScheduler Exception : " + e.getLocalizedMessage());
}
}
if (!isServiceRunning(context, MainService.class.getName())) {
try {
Intent intent = new Intent(context, MainService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
} catch (Exception e) {
Log.e(TAG, "Exception startService : " + e.getLocalizedMessage());
}
}
mainService = MainService.getInstance();
Log.e(TAG," MainSerivice : " + mainService);
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
handleUncaughtException(t, e);
}
});
}
public static boolean isServiceRunning(Context context, String serviceClassName) {
if (context == null || serviceClassName.equalsIgnoreCase("")) {
Log.i(TAG, "isServiceRunning called with context = null or service name blank");
return false;
}
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
for (ActivityManager.RunningServiceInfo runningServiceInfo : services) {
if (runningServiceInfo.service.getClassName().equals(serviceClassName))
return true;
}
return false;
}
}
导入android.app.ActivityManager;
导入android.app.Application;
导入android.app.job.JobInfo;
导入android.app.job.JobScheduler;
导入android.content.ComponentName;
导入android.content.ContentValues;
导入android.content.Context;
导入android.content.Intent;
导入android.net.Uri;
导入android.os.Build;
导入android.util.Log;
导入java.util.array;
导入java.util.List;
公共类MyApp扩展应用程序{
语境;
私有静态MyApp实例;
静态字符串TAG=“MyApp”;
主服务主服务;
作业调度器;
私有静态最终整型作业\u ID=1;
公共静态MyApp getInstance(){
返回实例;
}
@凌驾
public void onCreate(){
super.onCreate();
上下文=这个;
实例=此;
Log.i(标记“onCreate:”);
//android版本Lolipop(android 5.0)及以上版本的作业调度程序
if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.LOLLIPOP){
试一试{
jobScheduler=(jobScheduler)getSystemService(作业调度程序服务);
ComponentName jobService=新组件名(getPackageName(),XXJobService.class.getName());
Log.e(标记“onCreate:ComponentName:”+jobService);
JobInfo JobInfo=新建JobInfo.Builder(作业ID,作业服务)
.setPersisted(true)
.2000(5000)
.build();
int jobId=jobScheduler.schedule(作业信息);
if(jobId==JobScheduler.RESULT\u SUCCESS){
Log.e(标记“JobScheduler结果_SUCCESS”);
//Toast.makeText(上下文,“成功调度作业:+jobId,Toast.LENGTH_SHORT).show();
}否则{
Log.e(标记“JobScheduler结果\u失败:”+jobId);
//Toast.makeText(上下文,“RESULT\u FAILURE:+jobId,Toast.LENGTH\u SHORT).show();
}
}捕获(例外e){
Log.e(标记“JobScheduler异常:”+e.getLocalizedMessage());
}
}
如果(!isServiceRunning(上下文,MainService.class.getName())){
试一试{
意向意向=新意向(上下文,MainService.class);
if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.O){
启动地面服务(意向);
}否则{
startService(意向);
}
}捕获(例外e){
Log.e(标记“Exception startService:+e.getLocalizedMessage());
}
}
mainService=mainService.getInstance();
Log.e(标签“mainService:+mainService”);
setDefaultUncaughtExceptionHandler(新的Thread.UncaughtExceptionHandler(){
@凌驾
公共无效未捕获异常(线程t,可丢弃的e){
手部加速度异常(t,e);
}
});
}
公共静态布尔IServiceRunning(上下文上下文,字符串serviceClassName){
if(context==null | | serviceClassName.equalsIgnoreCase(“”){
i(标记“isServiceRunning调用时上下文为null或服务名称为空”);
返回false;
}
ActivityManager ActivityManager=(ActivityManager)context.getSystemService(context.ACTIVITY_服务);
List services=activityManager.getRunningServices(Integer.MAX_值);
对于(ActivityManager.RunningServiceInfo RunningServiceInfo:services){
if(runningServiceInfo.service.getClassName().equals(serviceClassName))
返回true;
}
返回false;
}
}
最后,放置一个bootupureceiver,以便在手机重启时自动启动认证和服务。它应该得到许可
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<receiver
android:name=".StartupReceiver"
android:enabled="true">
<intent-filter>
<action android:name="com.xx.MainService" />
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
服务未在后台连续运行。因此,我没有收到SIP呼叫的回调。