Android Management API tabanlı bir EMM olarak, cihazlardaki özel uygulamaları uzaktan yönetebilirsiniz. Bu işlemlere söz konusu uygulamaların yüklenmesi ve kaldırılması dahildir. Bu işlev, AMAPI SDK kullanılarak yerel olarak bir uzantı uygulaması geliştirilerek sağlanır.
Ön koşullar
- Uzantı uygulamanız AMAPI SDK ile entegre edilmiş olmalıdır.
- Cihaz tümüyle yönetiliyor olmalıdır.
- AMAPI SDK v1.6.0-rc01 veya sonraki bir sürümünün kullanılması gereklidir.
1. Uygulamanızı özelliği kullanmaya hazırlama
1.1. Uzantı uygulamanızda AMAPI SDK'sı ile entegrasyon yapma
Özel uygulama yönetimi süreci, AMAPI SDK'sını uzantı uygulamanıza entegre etmenizi gerektirir. Bu kitaplık ve uygulamanıza nasıl ekleneceği hakkında daha fazla bilgiyi AMAPI SDK entegrasyon kılavuzunda bulabilirsiniz.
1.2. FileProvider
özelliğini desteklemek için uygulamanızın manifest dosyasını güncelleyin
AndroidManifest.xml
öğesine<queries>
öğesini Android Cihaz Politikası (ADP) uygulaması için AMAPI SDK entegrasyon kılavuzunda gösterildiği şekilde ekleyin .- Aşağıdaki
<provider>
snippet'ini uygulamanızın<application>
etiketi içindekiAndroidManifest.xml
bölümüne uygulayın. Bu snippet, özel uygulama APK'sı paylaşılırken dosyaları depolamak ve AMAPI kullanılarak özel uygulamaların yüklenmesini sağlamak için kullanılır.
AndroidManifest.xml
:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.customapp">
<queries>
<package android:name="com.google.android.apps.work.clouddpc" />
</queries>
<application>
<!--This is used to store files when sharing the custom app apk.-->
<provider
android:name="com.google.android.managementapi.customapp.provider.CustomAppProvider"
android:authorities="${applicationId}.AmapiCustomAppProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_paths" />
</provider>
</application>
</manifest>
- Uygulamanızın
res/xml/
dizininde, özel APK'lerin depolama yolunu içeren yeni bir XML dosyası oluşturun.
file_provider_paths.xml
:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path
name="android_managementapi_custom_apks"
path="com.google.android.managementapi/customapp/apks/" />
</paths>
2. AMAPI SDK'sının özel uygulama özelliğiyle entegrasyon
2.1. Özel APK dosyasını yüklemeye hazırlama
Uygulamanın APK dosyası, dağıtılmadan önce kuruluma hazırlanmalıdır. Aşağıdaki kod snippet'inde bu süreç gösterilmektedir:
Kotlin
import android.net.Uri import androidx.core.net.Uri import java.io.File ... import com.google.android.managementapi.commands.LocalCommandClient import com.google.android.managementapi.commands.LocalCommandClient.InstallCustomAppCommandHelper import com.google.android.managementapi.commands.LocalCommandClientFactory ... fun prepareApkFile(): Uri? { // Get the storage location of custom APK files from AM API val client: LocalCommandClient = LocalCommandClientFactory.create(context) val installCustomAppCommandHelper = client.installCustomAppCommandHelper val customApksStorageDir: File = installCustomAppCommandHelper.customApksStorageDirectory ?: return null // Once you get hold of the custom APKs storage directory, you must store your custom APK // in that location before issuing the install command. val customApkFile: File = fetchMyAppToDir(customApksStorageDir) ?: return null val customApkFileUri: Uri = customApkFile.toUri() return customApkFileUri }
Java
import android.net.Uri; import androidx.core.net.Uri; import java.io.File; ... import com.google.android.managementapi.commands.LocalCommandClient; import com.google.android.managementapi.commands.LocalCommandClient.InstallCustomAppCommandHelper; import com.google.android.managementapi.commands.LocalCommandClientFactory; ... Uri prepareApkFile() { // Get the storage location of custom APK files from AM API LocalCommandClient client = LocalCommandClientFactory.create(); InstallCustomAppCommandHelper installCustomAppCommandHelper = client.getInstallCustomAppCommandHelper(); File customApksStorageDir = installCustomAppCommandHelper.getCustomApksStorageDirectory(); // Once you get hold of the custom APKs storage directory, you must store your custom APK // in that location before issuing the install command. File customApkFile = fetchMyAppToDir(customApksStorageDir); Uri customApkFileUri = Uri.fromFile(customApkFile); ... }
2.2. Özel bir uygulamanın yüklenmesi için istek gönderme
Aşağıdaki snippet'te, özel bir uygulamanın yüklenmesi için nasıl istek gönderileceği gösterilmektedir:
Kotlin
import android.content.Context import android.net.Uri import android.util.Log import com.google.android.managementapi.commands.LocalCommandClientFactory import com.google.android.managementapi.commands.model.Command import com.google.android.managementapi.commands.model.IssueCommandRequest import com.google.android.managementapi.commands.model.IssueCommandRequest.InstallCustomApp import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.guava.await import kotlinx.coroutines.withContext import java.lang.Exception private const val TAG = "MyClass" ... // Requires a file URI of the APK file. fun issueInstallCustomAppCommand(packageName: String, fileUri: Uri) { coroutineScope.launch { try { withContext(coroutineScope.coroutineContext) { val result: Command = LocalCommandClientFactory.create(context) .issueCommand(createInstallCustomAppRequest(packageName, fileUri)).await() // Process the returned command result here. Log.i(TAG, "Successfully issued command: $result") } } catch (t: Exception) { Log.e(TAG, "Failed to issue command", t) // Handle the exception (e.g., show an error message) } finally { // Make sure to clean up the apk file after the command is executed. cleanUpApkFile(fileUri) } } } private fun createInstallCustomAppRequest(packageName: String, fileUri: Uri): IssueCommandRequest { return IssueCommandRequest.builder() .setInstallCustomApp( InstallCustomApp.builder() .setPackageName(packageName) .setPackageUri(fileUri.toString()) .build() ) .build() } }
Java
import android.util.Log; ... import com.google.android.managementapi.commands.LocalCommandClientFactory; import com.google.android.managementapi.commands.model.Command; import com.google.android.managementapi.commands.model.GetCommandRequest; import com.google.android.managementapi.commands.model.IssueCommandRequest; import com.google.android.managementapi.commands.model.IssueCommandRequest.ClearAppsData; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; ... // Requires a file URI of the APK file. void issueInstallCustomAppCommand(String packageName, Uri fileUri) { Futures.addCallback( LocalCommandClientFactory.create(getContext()) .issueCommand(createInstallCustomAppRequest(packageName, fileUri)), new FutureCallback() { @Override public void onSuccess(Command result) { // Process the returned command result here. Log.i(TAG, "Successfully issued command"); } @Override public void onFailure(Throwable t) { Log.e(TAG, "Failed to issue command", t); } }, MoreExecutors.directExecutor()); } IssueCommandRequest createInstallCustomAppRequest(String packageName, Uri fileUri) { return IssueCommandRequest.builder() .setInstallCustomApp( InstallCustomApp.builder() .setPackageName(packageName) .setPackageUri(fileUri.toString()) .build() ) .build(); }
2.3. Yüklü uygulamaları almak için istekte bulunma
Kotlin
import android.content.Context import com.google.android.managementapi.device.DeviceClientFactory import com.google.android.managementapi.device.model.GetDeviceRequest import kotlinx.coroutines.guava.await suspend fun getInstalledApps(context: Context) = DeviceClientFactory.create(context) .getDevice(GetDeviceRequest.getDefaultInstance()) .await() .getApplicationReports()
Java
import android.content.Context; import com.google.android.managementapi.device.DeviceClientFactory; import com.google.android.managementapi.device.model.GetDeviceRequest; import com.google.android.managementapi.device.model.Device; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.List; import java.util.concurrent.Executor; public ListenableFuture<List> getInstalledApps() { ListenableFuture deviceFuture = DeviceClientFactory.create(context) .getDevice(GetDeviceRequest.getDefaultInstance()); return Futures.transform( deviceFuture, Device::getApplicationReports, executor // Use the provided executor ); }
3. Cihazı özel uygulama yönetimi politikalarıyla sağlama
Yönetmeyi planladığınız özel uygulamalarla bir
policy
oluşturun.{ "statusReportingSettings": { "applicationReportsEnabled": true }, "applications": [ { "signingKeyCerts": [ { "signingKeyCertFingerprintSha256": <sha256 signing key certificate hash value> } ], "packageName": "<emm_extensibility_app>", "installType": "AVAILABLE", "lockTaskAllowed": true, "defaultPermissionPolicy": "GRANT", "extensionConfig": { "notificationReceiver": "com.example.customapp.NotificationReceiverService" } }, { "signingKeyCerts": [ { "signingKeyCertFingerprintSha256": <sha256 signing key certificate hash value> }, ], "packageName": "<custom_app>", "installType": "CUSTOM", "lockTaskAllowed": true, "defaultPermissionPolicy": "GRANT", "customAppConfig": { "userUninstallSettings": "DISALLOW_UNINSTALL_BY_USER" } } ] } ```
allowPersonalUsage
,PERSONAL_USAGE_DISALLOWED
olarak ayarlanmışken enterprises.enrollmentTokens.create işlevini çağırarak cihaz için bir kayıt jetonu oluşturun.Cihazı kayıt jetonuyla tümüyle yönetilen modda hazırlayın.
Genişletilebilirlik uygulamanızı Managed Play'den yükleyin.
Genişletilebilirlik uygulamanız:
- özel uygulamanın APK dosyasını indirebilir.
- Özel uygulamanın yüklenmesi için istekte bulunabilir (daha önce gösterilen kod snippet'ine bakın).
- yanıt almalıdır.
API
Sunucu-istemci API'si
Listelenen yeni alanlara ve numaralandırılmış değerlere bakın: