Unity项目创建Android前台服务遇阻求助(含Firebase冲突)
Hey Abdul, let's break down your issues step by step since you're new to this—no worries, these are super common pitfalls when bridging Unity and Android! I'll cover both the Firebase Activity mix-up and the service launch failure with actionable fixes.
1. 为什么拿到的是Firebase Activity而非Unity Activity
当你在Unity项目中集成Firebase后,Firebase会用自己的代理Activity(比如FirebaseUnityActivity)包装原有的UnityPlayerActivity,这是正常行为。不过直接持有Activity引用可能会导致内存泄漏,更安全的做法是使用Application Context,它的生命周期和整个应用一致,适合长期持有。
2. 修复服务启动失败问题
你的代码有几个关键漏洞导致服务无法启动:
- Intent设置不正确(用Action而非直接指定服务类)
- 未处理Android版本差异(Android 8.0+对前台服务有严格规则)
- AndroidManifest中缺少服务注册和必要权限
步骤1:更新Android库代码
重写库代码,改用Application Context并适配现代Android要求:
import android.content.Context; import android.content.Intent; import android.os.Build; import android.util.Log; public class Unity_Native_Event { private static Context _appContext; // 接收Application Context而非Activity,避免内存泄漏 public static void ReceiveContextInstance(Context context) { Log.d("XR Service", "ReceiveContextInstance: "+context); _appContext = context.getApplicationContext(); } public static void StartMyService() { if (_appContext == null) { Log.e("XR Service", "Application Context为空!请先调用ReceiveContextInstance"); return; } // 直接指定服务类(比用Action更可靠) Intent intent = new Intent(_appContext, CustomService.class); // 适配Android 8.0+的前台服务启动规则 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { _appContext.startForegroundService(intent); } else { _appContext.startService(intent); } } }
步骤2:更新Unity脚本
修改Unity代码,传递Application Context而非Activity,并调整调用时机确保上下文就绪:
using UnityEngine; public class LocationServiceManager : MonoBehaviour { AndroidJavaClass unityClass; AndroidJavaObject unityActivity; AndroidJavaClass customClass; private void Start() { // 等到Start()再调用,确保Activity完全初始化 sendContextReference("com.abc.xy.location.customlibrary.Unity_Native_Event"); startService(); } void sendContextReference(string packageName) { unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); unityActivity = unityClass.GetStatic<AndroidJavaObject>("currentActivity"); // 从Activity获取Application Context AndroidJavaObject appContext = unityActivity.Call<AndroidJavaObject>("getApplicationContext"); Debug.Log($"ReceiveContextInstance: {appContext.ToString()}"); customClass = new AndroidJavaClass(packageName); customClass.CallStatic("ReceiveContextInstance", appContext); } void startService() { if (customClass != null) { customClass.CallStatic("StartMyService"); } else { Debug.LogError("自定义Android类未初始化!"); } } }
步骤3:正确注册服务与权限
将以下内容添加到AndroidManifest.xml(可以放在自定义库中,也可以放在Unity的Plugins/Android文件夹下):
<!-- 位置服务和前台服务所需权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <application> <!-- 注册前台服务 --> <service android:name="com.abc.xy.location.customlibrary.CustomService" android:foregroundServiceType="location" <!-- Android 12+ 位置服务必填 --> android:exported="false"> </service> </application>
步骤4:实现带通知的前台服务
Android 8.0+要求前台服务必须显示持久通知,更新你的CustomService类:
import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Service; import android.content.Intent; import android.os.Build; import android.os.IBinder; import androidx.core.app.NotificationCompat; public class CustomService extends Service { private static final int NOTIFICATION_ID = 1001; private static final String CHANNEL_ID = "LocationServiceChannel"; @Override public void onCreate() { super.onCreate(); // 为Android 8.0+创建通知渠道 createNotificationChannel(); // 显示前台通知 Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("位置服务运行中") .setContentText("正在上传你的位置到服务器") .setSmallIcon(R.drawable.ic_notification) // 替换为你的应用通知图标 .build(); startForeground(NOTIFICATION_ID, notification); } private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "位置服务通知", NotificationManager.IMPORTANCE_LOW); NotificationManager manager = getSystemService(NotificationManager.class); if (manager != null) { manager.createNotificationChannel(channel); } } } @Nullable @Override public IBinder onBind(Intent intent) { return null; // 不需要绑定服务,返回null } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 在这里添加位置获取和服务器上传逻辑 return START_STICKY; // 服务被系统杀死后尝试重启 } }
3. 新手调试小技巧
- 查看Unity的Logcat找错误(重点关注
ActivityNotFoundException、NullPointerException或权限拒绝信息) - 确保自定义库的
.aar文件放在Unity的Plugins/Android文件夹中 - 用实体Android设备测试(模拟器可能存在位置和服务的兼容性问题)
- 记得在Unity中动态申请位置权限(Android 6.0+需要手动申请)
内容的提问来源于stack exchange,提问作者Abdul Qadir

