Bu kılavuzda, Unity uygulamasından özel bir süreçte Android'de algılanabilir bir hizmet (ön plan hizmeti veya FGS) çalıştırmak için gereken yapılandırma ve uygulama ele alınmaktadır.
1. Algılanabilir hizmet desteğini yapılandırma
Bu bölümde, gerekli izinlerin nasıl ayarlanacağı ve hizmetin projenizin manifest dosyasında nasıl beyan edileceği açıklanmaktadır.
1.1 İzinler ve hizmet beyanı
Özel
Assets/Plugins/Android/AndroidManifest.xml
başlatıcı etkinliğini, algılanabilir hizmet izinlerini,
bildirim iznini, ağ iznini ve hizmeti bildirmelidir:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.INTERNET" />
<application>
<activity
android:name="com.unity3d.player.UnityPlayerActivity"
android:theme="@style/UnityThemeSelector"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
<service
android:name="com.sample.fgs.DownloadService"
android:process=":downloader"
android:exported="false"
android:stopWithTask="false"
android:foregroundServiceType="dataSync" />
</application>
</manifest>
foregroundServiceType
gerçek işlevle eşleşmelidir: dataSync aktarım, mediaPlayback oynatma, location konum izleme. İlgili FOREGROUND_SERVICE_<TYPE> izni ve startForeground çağrısıyla eşleşmelidir. Üçü de tutarlı olmalıdır. Aksi takdirde hizmet başlatılamaz.
1.2 Hizmet süreci Java'sını Unity projesine ekleme
FGS hizmeti işlemi Java'yı çalıştırır. Hizmet uygulaması Java kodunu bir JAR dosyası olarak paketleyin ve Assets/Plugins/Android/ altına yerleştirin. Unity, bu dizindeki JAR dosyalarını Gradle'ın libs/input'una otomatik olarak dahil eder ve APK'ya paketler. Hizmet süreci bu sınıfları çalışma zamanında yükler. Hizmeti Java veya Kotlin'de uygulama hakkında daha fazla bilgi için Java uygulaması başlıklı makaleyi inceleyin.
2. Ayrı bir işlem yapılandırma
Süreç sınırı, bir manifest özelliğiyle etkinleştirilir:
android:process=":downloader"
Baştaki iki nokta üst üste işareti, your.package.name:downloader adlı uygulamaya özel bir işlem oluşturur. Ana işlemden farklı bir PID'ye sahiptir ve ana işlem sonlandırıldıktan sonra çalışmaya devam edebilir.
2.1 Servis sürecinde Unity yok
Unity'nin libunity.so, IL2CPP çalışma zamanı ve benzerlerinin hizmet sürecine dahil edilmesini önlemek için hizmet tarafındaki Java, UnityPlayer.currentActivity dahil olmak üzere herhangi bir Unity sınıfını kullanmamalı ve yalnızca Android Context, Intent ekstraları ve platform API'lerine bağlı olmalıdır. Unity motoru çalışma zamanı yalnızca ana işlemin UnityPlayerActivity aracılığıyla yüklenir. Özel :downloader işlemi bu kitaplıkları yüklemez. Bu nedenle, hizmet işleminde Unity sınıflarına referans verilmesi işe yaramaz.
2.2 İşlem başlangıç giriş noktaları
Ana işlem startForegroundService'i çağırdıktan sonra sistem, :downloader hizmet sürecini çatallandırır:
Applicationöğesini oluşturur veApplication.onCreateöğesini çağırır. Bu işlem her süreçte çalışır. Bu nedenle, hizmet süreci tarafından gereken başlatma işlemi burada tekrar yapılmalıdır. Daha fazla bilgi için 2.3 bölümüne bakın.DownloadServiceoluşturur veonCreateçağırır. Bu, hizmet süreci giriş noktasıdır.- Başlangıçta oluşturulan Intent ile
onStartCommandgeri çağrılır. Hizmet burada kendini ön plana çıkarır ve çalışanı başlatır. Daha fazla bilgi için bölüm 3.1'e bakın.
2.3 Durum, işlem başına bir kez bulunur
Dex kodu salt okunur olarak paylaşılır ancak çalışma zamanı durumu paylaşılmaz:
Application.attachBaseContextveApplication.onCreate, uygulama bileşenlerini barındıran her süreçte çalışır.- Statik başlatıcılar ve statik alanlar, her süreçte bağımsız olarak bulunur. Ana süreçte statik bir alan atandığında hizmetle iletişim kurulmaz.
- Unity, C# ve Etkinlikler ana süreçte kalır.
3. Java uygulaması
Bu bölümde, FGS modülünün Java tarafı ele alınmaktadır: 3.1 ve 3.2, hizmet sürecinde DownloadService; 3.3 ise ana süreçte FgsBridge (JNI kullanılarak yapılan C# çağrıları için giriş noktası) yer alır.
3.1 Önce ön plana çıkarma
public class DownloadService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
startForegroundCompat();
// Start the download thread; must come after promoting to foreground
// ...
} catch (Exception e) {
Log.e(TAG, "onStartCommand() failed [errorType="
+ e.getClass().getSimpleName() + "]: " + e.getMessage(), e);
stopSelf();
}
return START_NOT_STICKY;
}
private void startForegroundCompat() {
Notification notification = buildNotification(0L);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(NOTIFICATION_ID, notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
} else {
startForeground(NOTIFICATION_ID, notification);
}
}
...
3.2 Bildirimi ekleme
Algılanabilir bir hizmetin, ilerlemeyi bildirmek için bildirim kanalında devam eden bir bildirime ihtiyacı vardır. Bildirimde, hizmeti durdurmak için PendingIntent.getService kullanılarak hizmete ACTION_STOP gönderen bir Durdur işlemi bulunur.
private Notification buildNotification(long progressBytes) {
int progressMib = (int) (progressBytes / MIB);
Intent launchIntent = getPackageManager().getLaunchIntentForPackage(getPackageName());
PendingIntent contentIntent = launchIntent != null
? PendingIntent.getActivity(this, 0, launchIntent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT)
: null;
Intent stopIntent = new Intent(this, DownloadService.class)
.setAction(ACTION_STOP);
PendingIntent stopPendingIntent = PendingIntent.getService(this, 0,
stopIntent, PendingIntent.FLAG_IMMUTABLE
| PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder builder = new Notification.Builder(this,
CHANNEL_ID)
.setContentTitle("Download service")
.setContentText("Downloaded " + progressMib + " MB / " + TOTAL_MIB + " MB")
.setSmallIcon(android.R.drawable.stat_sys_download)
.setProgress(TOTAL_MIB, progressMib, false)
.setOngoing(true)
.setOnlyAlertOnce(true)
.addAction(new Notification.Action.Builder(null,
"Stop", stopPendingIntent).build());
if (contentIntent != null) {
builder.setContentIntent(contentIntent);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
builder.setForegroundServiceBehavior(
Notification.FOREGROUND_SERVICE_IMMEDIATE);
}
return builder.build();
}
3.3 Java ana makine giriş noktası
FgsBridge, ana işlemin FGS'yi kontrol etmek için kullandığı Java giriş noktasıdır (hizmet işleminde değil, ana işlemde çalışır). C#, hizmeti başlatmak ve durdurmak, bildirim iznini işlemek için JNI'yi kullanarak bu statik yöntemleri çağırır:
public class FgsBridge {
// Start the :downloader perceptible service and begin downloading
public static void startDownloadService(Context context) {
try {
context.startForegroundService(new Intent(context, DownloadService.class));
} catch (Exception e) {
Log.e(TAG, "startDownloadService() failed [errorType="
+ e.getClass().getSimpleName() + "]: " + e.getMessage(), e);
}
}
// Stop the service: sends a stop intent; the service removes its
// notification before exiting
public static void stopDownloadService(Context context) {
try {
context.startService(new Intent(context, DownloadService.class)
.setAction(ACTION_STOP));
} catch (Exception e) {
Log.e(TAG, "stopDownloadService() failed [errorType="
+ e.getClass().getSimpleName() + "]: " + e.getMessage(), e);
}
}
// Request notification permission (only needed on API 33+; if already
// granted, no dialog is shown and it returns immediately)
public static void requestNotificationPermission(Activity activity) {
if (Build.VERSION.SDK_INT < 33) {
return;
}
try {
activity.requestPermissions(
new String[] { POST_NOTIFICATIONS }, NOTIFICATION_PERMISSION_REQUEST);
} catch (Exception e) {
Log.e(TAG, "requestNotificationPermission() failed [errorType="
+ e.getClass().getSimpleName() + "]: " + e.getMessage(), e);
}
}
}
4. Unity'den (C#) FGS'yi başlatma ve kontrol etme
AndroidBridge, JNI kullanarak FgsBridge'yi çağıran C# sarmalayıcısıdır. Üç yöntem uygulaması:
public static void StartDownloadService()
{
#if UNITY_ANDROID && !UNITY_EDITOR
CallStatic("startDownloadService");
#else
Debug.Log("StartDownloadService() no-op outside Android");
#endif
}
public static void StopDownloadService()
{
#if UNITY_ANDROID && !UNITY_EDITOR
CallStatic("stopDownloadService");
#else
Debug.Log("StopDownloadService() no-op outside Android");
#endif
}
public static void RequestNotificationPermission()
{
#if UNITY_ANDROID && !UNITY_EDITOR
CallStatic("requestNotificationPermission");
#else
Debug.Log("RequestNotificationPermission() no-op outside Android");
#endif
}
CallStatic, FgsBridge sınıfını çözen ve ilgili Java statik yöntemini çağıran dahili bir JNI yardımcı programıdır. RequestNotificationPermission
Bildirimin hizmet süreci başladığında hemen görünmesi için uygulama başlatılırken çağrılmalıdır.