You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 8.0+后台Sinch推送示例失效问题求助

解决Sinch推送在Android 8.0+后台/未运行状态下失效的问题

我明白你现在遇到的头疼问题——Sinch的推送示例在Android 8.0及以上系统的后台或未运行状态下完全失效,但低版本系统却能正常工作,而且你已经确认自己的FCM实现是没问题的,试过站内各种方案都没搞定。结合你贴的代码,我来帮你梳理几个关键的排查点和修复方案:


1. 应对Android 8.0+的后台Service限制

Android 8.0(API 26)引入了后台Service限制,系统会限制后台应用启动Service的能力,而你在FcmListenerService里用BIND_AUTO_CREATE绑定SinchService的方式,在后台场景下很可能绑定失败——因为FcmListenerService是短生命周期的组件,系统会很快回收它,导致SinchService无法正常启动。

修复方案:将SinchService设为前台服务

修改SinchService的start()方法,当系统版本≥API 26时,启动前台服务并显示一个持久化通知(这是Android O+的强制要求):

private void start(String username) {
    boolean permissionsGranted = true;
    if (mSinchClient == null) {
        mSettings.setUsername(username);
        createClient(username);
    }
    try {
        mSinchClient.checkManifest();
    } catch (MissingPermissionException e) {
        // 权限处理逻辑保持不变
        permissionsGranted = false;
        // ... 省略原有代码
    }
    if (permissionsGranted) {
        Log.d(TAG, "Starting SinchClient");
        // 添加前台服务逻辑
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createSinchNotificationChannel();
            Notification notification = new NotificationCompat.Builder(this, "SINCH_CALL_CHANNEL")
                    .setContentTitle("Sinch服务运行中")
                    .setContentText("正在监听来电")
                    .setSmallIcon(R.drawable.icon)
                    .setPriority(NotificationCompat.PRIORITY_LOW)
                    .build();
            startForeground(1001, notification);
        }
        mSinchClient.start();
    }
}

// 新增创建通知渠道的方法
private void createSinchNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel = new NotificationChannel(
                "SINCH_CALL_CHANNEL",
                "Sinch来电通知",
                NotificationManager.IMPORTANCE_DEFAULT
        );
        channel.setDescription("用于接收Sinch来电推送");
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(channel);
    }
}

同时在onDestroy()里停止前台服务:

@Override
public void onDestroy() {
    if (mSinchClient != null && mSinchClient.isStarted()) {
        mSinchClient.terminate();
    }
    // 停止前台服务
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        stopForeground(true);
    }
    super.onDestroy();
}

2. 修正Push Relay时的SinchClient初始化逻辑

看你SinchServiceInterface里的relayRemotePushNotificationPayload方法,当mSinchClient为null时,你只创建了Client但没有等待它启动完成就调用relay——而SinchClient的启动是异步的,这会导致推送无法被正确处理。

修复方案:等待SinchClient启动完成后再处理推送

修改relayRemotePushNotificationPayload方法,确保Client启动后再relay推送:

public NotificationResult relayRemotePushNotificationPayload(final Map payload) {
    if (mSinchClient == null && !mSettings.getUsername().isEmpty()) {
        createClient(mSettings.getUsername());
        // 添加监听等待Client启动
        mSinchClient.addSinchClientListener(new SinchClientListener() {
            @Override
            public void onClientStarted(SinchClient client) {
                // 启动完成后处理推送
                client.relayRemotePushNotificationPayload(payload);
                // 移除监听避免内存泄漏
                client.removeSinchClientListener(this);
            }

            @Override
            public void onClientFailed(SinchClient client, SinchError error) {
                Log.e(TAG, "SinchClient启动失败: " + error.getMessage());
                client.removeSinchClientListener(this);
            }

            // 实现其他必要的空方法
            @Override public void onClientStopped(SinchClient client) {}
            @Override public void onLogMessage(int level, String area, String message) {}
            @Override public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration clientRegistration) {}
        });
        // 启动SinchClient
        try {
            mSinchClient.checkManifest();
            mSinchClient.start();
        } catch (MissingPermissionException e) {
            Log.e(TAG, "启动SinchClient缺少权限: " + e.getRequiredPermission());
            return null;
        }
        // 异步启动阶段暂时返回null,推送会在启动完成后处理
        return null;
    } else if (mSinchClient == null && mSettings.getUsername().isEmpty()) {
        Log.e(TAG, "没有保存的用户名,无法启动SinchClient处理推送");
        return null;
    } else if (!mSinchClient.isStarted()) {
        // 如果Client存在但未启动,先启动再处理
        mSinchClient.start();
        mSinchClient.addSinchClientListener(new SinchClientListener() {
            @Override
            public void onClientStarted(SinchClient client) {
                client.relayRemotePushNotificationPayload(payload);
                client.removeSinchClientListener(this);
            }

            @Override public void onClientFailed(SinchClient client, SinchError error) {
                Log.e(TAG, "SinchClient重启失败: " + error.getMessage());
                client.removeSinchClientListener(this);
            }

            // 其他空方法实现
            @Override public void onClientStopped(SinchClient client) {}
            @Override public void onLogMessage(int level, String area, String message) {}
            @Override public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration clientRegistration) {}
        });
        return null;
    }
    // Client已启动,直接处理推送
    return mSinchClient.relayRemotePushNotificationPayload(payload);
}

3. 确保Notification Channel提前创建

你的FcmListenerService里只在收到推送时才创建通知渠道,但Android 8.0+要求通知渠道必须在显示通知前存在。如果Sinch自己生成通知(比如来电通知),而此时渠道还没创建,通知就会失效。

修复方案:在App启动时创建通知渠道

在自定义的Application类的onCreate()方法里调用通知渠道创建逻辑:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // 创建Sinch相关的通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    "SINCH_CALL_CHANNEL",
                    "Sinch来电通知",
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            channel.setDescription("用于接收Sinch来电推送");
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
    }
}

记得在AndroidManifest.xml里配置这个Application类:

<application
    android:name=".MyApplication"
    <!-- 其他配置 -->
>

4. 处理Android 10+的后台启动限制

Android 10(API 29)及以上系统对后台启动的限制更严格,即使是前台服务,如果App被系统杀死,也可能无法自动启动。此时需要引导用户允许App忽略电池优化。

修复方案:申请忽略电池优化权限

  1. 在AndroidManifest.xml里添加权限:
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
  1. 在用户登录成功后或首次启动时,请求该权限:
private void requestBatteryOptimizationPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
        String packageName = getPackageName();
        if (!pm.isIgnoringBatteryOptimizations(packageName)) {
            Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
            intent.setData(Uri.parse("package:" + packageName));
            startActivity(intent);
        }
    }
}

5. 验证Sinch的托管推送配置

最后,确保你在Sinch控制台的配置是正确的:

  • 确认FCM的Server Key已正确配置(在Sinch控制台的App Settings > Push > Firebase Cloud Messaging里)
  • 确认App的包名和Sinch控制台里的包名完全一致
  • 确保你的App已经将FCM Token注册到Sinch,在获取到FCM Token后调用:
FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> {
    if (task.isSuccessful() && task.getResult() != null && mSinchClient != null && mSinchClient.isStarted()) {
        mSinchClient.registerPushToken(task.getResult());
    }
});

按照上面的步骤逐一修复后,应该就能解决Android 8.0+系统下后台/未运行状态的Sinch推送问题了。

内容的提问来源于stack exchange,提问作者Arya pyaa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:13:54