Android'de Özel Korumalı Alan dokümanlarını okurken, çalıştığınız program sürümünü seçmek için Geliştirici Önizlemesi veya Beta düğmesini kullanın, talimatlar farklılık gösterebilir.
SDK Çalışma Zamanı, SDK'ların çağrı yapan uygulamadan ayrı özel bir korumalı alanda çalışmasına olanak tanır. SDK Çalışma Zamanı, kullanıcı verilerinin toplanmasıyla ilgili gelişmiş güvenlik önlemleri ve garantiler sağlar. Bu işlem, veri erişim haklarını ve izin verilen izinler grubunu sınırlayan değiştirilmiş bir yürütme ortamı aracılığıyla gerçekleştirilir. Tasarım teklifinde SDK Çalışma Zamanı hakkında daha fazla bilgi edinebilirsiniz.
Bu sayfadaki adımlar, çağrı yapan bir uygulamada uzaktan oluşturulabilecek web tabanlı bir görünüm tanımlayan çalışma zamanı etkin SDK oluşturma işleminde size yol gösterir.
Bilinen sınırlamalar
SDK Çalışma Zamanı ile ilgili devam etmekte olan özelliklerin listesi için sürüm notlarına bakın.
Aşağıdaki sınırlamaların, bir sonraki ana Android platformu sürümünde düzeltilmesi beklenmektedir.
- Kaydırılabilir görünümde reklam oluşturma. Örneğin,
RecyclerView
düzgün çalışmaz.- Yeniden boyutlandırmada duraklamalar yaşayabilirsiniz.
- Kullanıcı dokunma kaydırma etkinlikleri, çalışma zamanına doğru şekilde iletilmiyor.
- Storage API
- SDK başına depolama özelliği Android 13'te mevcut değildir.
Aşağıdaki sorun 2023'te düzeltilecektir:
- Bu API'ler için destek henüz etkinleştirilmediğinden
getAdId
vegetAppSetId
API'leri henüz düzgün çalışmıyor.
Başlamadan önce
Başlamadan önce aşağıdaki adımları tamamlayın:
Android'de Özel Korumalı Alan için geliştirme ortamınızı ayarlayın. SDK Çalışma Zamanı'nı destekleyen araçlar geliştirme aşamasında olduğundan bu kılavuzda Android Studio'nun Canary sürümünü kullanmanız gerekmektedir. Android Studio'nun bu sürümünü, kullandığınız diğer sürümlere paralel olarak çalıştırabilirsiniz. Bu nedenle, bu gereksinim sizin için uygun değilse lütfen bize bildirin.
Desteklenen bir cihaza sistem görüntüsü yükleyin veya Android'de Özel Korumalı Alan desteği içeren bir emülatör oluşturun.
Android Studio'da projenizi oluşturma
SDK Çalışma Zamanı'nı denemek için istemci-sunucu modeline benzer bir model kullanın. Temel fark, uygulamaların (istemci) ve SDK'ların ("sunucu") aynı cihazda çalışmasıdır.
- Projenize bir uygulama modülü ekleyin. Bu modül, SDK'yı çalıştıran istemci olarak hizmet verir.
- Uygulama modülünüzde SDK Çalışma Zamanı'nı etkinleştirin, gerekli izinleri tanımlayın ve API'ye özel reklam hizmetlerini yapılandırın.
- Projenize bir kitaplık modülü ekleyin. Bu modül SDK kodunuzu içerir.
- SDK modülünüzde gerekli izinleri tanımlayın. Bu modülde API'ye özel reklam hizmetlerini yapılandırmanız gerekmez.
- SDK'nızın kullanmadığı kitaplık modülünüzün
build.gradle
dosyasındakidependencies
öğesini kaldırın. Çoğu durumda, tüm bağımlılıkları kaldırabilirsiniz. Bunu, adı SDK'nıza karşılık gelen yeni bir dizin oluşturarak yapabilirsiniz. com.android.privacy-sandbox-sdk
türünü kullanarak manuel olarak yeni bir modül oluşturun. Cihazınıza dağıtılabilecek bir APK oluşturmak için SDK koduyla birlikte sunulur. Bunu, adı SDK'nıza karşılık gelen yeni bir dizin oluşturarak yapabilirsiniz. Boş birbuild.gradle
dosyası ekleyin. Bu dosyanın içeriği, bu kılavuzun ilerleyen bölümlerinde doldurulacaktır.gradle.properties
dosyanıza şu snippet'i ekleyin:android.experimental.privacysandboxsdk.enable=true
TiramisuPrivacySandbox emülatör görüntüsünü indirin ve bu görüntüyle Play Store'u içeren bir emülatör oluşturun.
SDK geliştiricisi veya uygulama geliştiricisi olmanıza bağlı olarak önceki paragrafta açıklanandan farklı bir nihai kurulumunuz olabilir.
SDK'yı, Android Studio veya Android Debug Bridge (ADB) kullanarak, uygulama yüklerken olduğu gibi bir test cihazına yükleyin. Başlamanıza yardımcı olmak için Kotlin ve Java programlama dillerinde örnek uygulamalar oluşturduk. Bunları GitHub deposunda bulabilirsiniz. README ve manifest dosyalarında, örneği Android Studio'nun kararlı sürümlerinde çalıştırmak için nelerin değiştirilmesi gerektiğini açıklayan yorumlar vardır.
SDK'nızı hazırlama
Modül düzeyinde bir dizini manuel olarak oluşturun. Bu paket, SDK APK'sını oluşturmak için uygulama kodunuzun çevresinde sarıcı görevi görür. Yeni dizine bir
build.gradle
dosyası ekleyin ve bu dosyayı aşağıdaki snippet ile doldurun. Çalışma zamanı özellikli SDK'nız (RE-SDK) için benzersiz bir ad kullanın ve bir sürüm sağlayın. Kitaplık modülünüzüdependencies
bölümüne dahil edin.plugins { id 'com.android.privacy-sandbox-sdk' } android { compileSdkPreview 'TiramisuPrivacySandbox' minSdkPreview 'TiramisuPrivacySandbox' namespace = "com.example.example-sdk" bundle { packageName = "com.example.privacysandbox.provider" sdkProviderClassName = "com.example.sdk_implementation.SdkProviderImpl" setVersion(1, 0, 0) } } dependencies { include project(':<your-library-here>') }
Uygulama kitaplığınızda SDK'nız için giriş noktası olarak kullanılacak bir sınıf oluşturun. Sınıfın adı
sdkProviderClassName
değeriyle eşleşmeli veSandboxedSdkProvider
değerine genişlemelidir.
SDK'nızın giriş noktasının kapsamı SandboxedSdkProvider
. SandboxedSdkProvider
, SDK'nız için getContext()
yöntemini çağırarak erişebileceğiniz bir Context
nesnesi içerir. Bu bağlama yalnızca onLoadSdk()
çağrıldıktan sonra erişilmelidir.
SDK uygulamanızın derlemesini sağlamak için SDK yaşam döngüsünü ele alacak yöntemleri geçersiz kılmanız gerekir:
onLoadSdk()
Korumalı alanda SDK'yı yükler ve SDK, istekleri işlemeye hazır olduğunda arayüzünü yeni bir
SandboxedSdk
nesnesi içine sarmalanmışIBinder
nesnesi olarak ileterek çağıran uygulamayı bilgilendirir. Bağlı hizmetler kılavuzu,IBinder
özelliğini sunmanın farklı yollarını sağlar. İstediğiniz yöntemi seçebilirsiniz ancak bu seçim SDK ve çağrı yapan uygulama için tutarlı olmalıdır.Örnek olarak AIDL'yi kullanarak, uygulama tarafından paylaşılacak ve kullanılacak
IBinder
öğenizi sunmak için bir AIDL dosyası tanımlamanız gerekir:// ISdkInterface.aidl interface ISdkInterface { // the public functions to share with the App. int doSomething(); }
getView()
Reklamınızın görünümünü oluşturup ayarlar, görünümü diğer herhangi bir Android görünümüyle aynı şekilde başlatır ve görünümü, piksel cinsinden belirli bir genişlik ve yükseklikte bir pencerede uzaktan oluşturulacak bir şekilde döndürür.
Aşağıdaki kod snippet'inde bu yöntemlerin nasıl geçersiz kılınacağı gösterilmektedir:
Kotlin
class SdkProviderImpl : SandboxedSdkProvider() { override fun onLoadSdk(params: Bundle?): SandboxedSdk { // Returns a SandboxedSdk, passed back to the client. The IBinder used // to create the SandboxedSdk object is used by the app to call into the // SDK. return SandboxedSdk(SdkInterfaceProxy()) } override fun getView(windowContext: Context, bundle: Bundle, width: Int, height: Int): View { val webView = WebView(windowContext) val layoutParams = LinearLayout.LayoutParams(width, height) webView.setLayoutParams(layoutParams) webView.loadUrl("https://developer.android.com/privacy-sandbox") return webView } private class SdkInterfaceProxy : ISdkInterface.Stub() { fun doSomething() { // Implementation of the API. } } }
Java
public class SdkProviderImpl extends SandboxedSdkProvider { @Override public SandboxedSdk onLoadSdk(Bundle params) { // Returns a SandboxedSdk, passed back to the client. The IBinder used // to create the SandboxedSdk object is used by the app to call into the // SDK. return new SandboxedSdk(new SdkInterfaceProxy()); } @Override public View getView(Context windowContext, Bundle bundle, int width, int height) { WebView webView = new WebView(windowContext); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(width, height); webView.setLayoutParams(layoutParams); webView.loadUrl("https://developer.android.com/privacy-sandbox"); return webView; } private static class SdkInterfaceProxy extends ISdkInterface.Stub { @Override public void doSomething() { // Implementation of the API. } } }
SdkSandboxController
SdkSandboxController
, SDK'lar tarafından kullanılabilen bağlam tabanlı bir sistem hizmeti sarmalayıcıdır. Bu işlev, SandboxedSdkProvider#getContext()
kaynağından alınan bağlamı kullanan ve bu bağlamda context.getSystemService(SdkSandboxController.class)
çağrısı yapılarak SDK'lar tarafından alınabilir. Denetleyici, SDK'ların Özel Korumalı Alan ile etkileşime girmesine ve bilgi edinmesine yardımcı olan API'lere sahiptir.
Denetleyicideki çoğu API, SandboxedSdkContext
erişim için kullanılan bağlam değilse istisna bildirir. Hizmet sarmalayıcıyı diğer bağlamlarda kullanılamaz hale getirmeyi planlıyoruz. SdkSandboxController
, SDK sağlayıcılar tarafından kullanılmak üzere tasarlanmıştır ve uygulama geliştiricilerin kullanması önerilmez.
SDK ile SDK iletişimi
Çalışma zamanındaki SDK'lar, uyumlulaştırmayı ve ilgili kullanım alanlarını desteklemek için birbirleriyle iletişim kurabilmelidir. Burada açıklanan araç seti, korumalı alandaki diğer SDK'ların kullanımına sunulan SDK'larla çalışmak için bir arayüz sağlar. Bu SDK Çalışma Zamanı uygulaması, SDK ile SDK iletişimi etkinleştirmeye yönelik ilk adımdır ve Özel Korumalı Alan'da uyumlulaştırma ile ilgili tüm kullanım alanlarını henüz kapsamayabilir.
SdkSandboxController
öğesindeki getSandboxedSdks()
API, Özel Korumalı Alan'da yüklenen tüm SDK'lar için bir SandboxedSdk
sınıfı sağlar. SandboxedSdk
nesnesi, SDK ile ilgili ayrıntıları ve istemcilerin SDK ile iletişim kurabilmesi için sdkInterface
içerir.
Özel Korumalı Alan'daki SDK'ların, diğer SDK'larla konuşmak için aşağıdakine benzer kod snippet'leri kullanması beklenir. Bu kodun, "SDK1"in "SDK2" ile iletişim kurmasını sağlamak amacıyla yazıldığını varsayalım. Her ikisi de uygulama tarafından Özel Korumalı Alan'da yüklenir.
SdkSandboxController controller = mSdkContext
.getSystemService(SdkSandboxController.class);
List<SandboxedSdk> sandboxedSdks = controller.getSandboxedSdks();
SandboxedSdk sdk2 = sandboxedSdks.stream().filter( // The SDK it wants to
// connect to, based on SDK name or SharedLibraryInfo.
try {
IBinder binder = sdk2.getInterface();
ISdkApi sdkApi = ISdkApi.Stub.asInterface(binder);
// Call API on SDK2
message = sdkApi.getMessage();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
Yukarıdaki örnekte SDK1, SDK2'nin AIDL kitaplığını bağımlılık olarak ekler. Bu istemci SDK'sı, AIDL tarafından oluşturulan Bağlayıcı kodu içeriyor. Her iki SDK da bu AIDL kitaplığını dışa aktarmalıdır. Bu, uygulamaların Özel Korumalı Alan'daki SDK'larla iletişim kurduklarında yapmaları beklenenlerle aynıdır.
SDK'lar arasında arayüz paylaşımı için otomatik oluşturulan yöntem desteği, gelecekteki bir güncellemede eklenecektir.
Çalışma zamanındaki SDK'ların, henüz çalışma zamanı özelliğinin etkinleştirilmediği uygulama bağımlılıkları ve reklam SDK'larıyla iletişim kurması gerekebilir.
SdkSandboxManager
uygulamasındaki registerAppOwnedSdkSandboxInterface()
API, çalışma zamanı özelliği etkin olmayan SDK'ların arayüzlerini platforma kaydetmeleri için bir yol sağlar. SdkSandboxController
uygulamasındaki getAppOwnedSdkSandboxInterfaces()
API, kayıtlı ve statik olarak bağlantılı tüm SDK'lar için AppOwnedSdkSandboxInterface
sağlar.
Aşağıdaki örnekte, çalışma zamanı özellikli SDK iletişimi için kullanılabilir hale getirmek üzere arayüzlerin nasıl kaydedileceği gösterilmektedir:
// Register AppOwnedSdkSandboxInterface
mSdkSandboxManager.registerAppOwnedSdkSandboxInterface(
new AppOwnedSdkSandboxInterface(
APP_OWNED_SDK_NAME, (long) APP_OWNED_SDK_VERSION, new AppOwnedSdkApi())
);
Bu örnekte, çalışma zamanının etkin olmadığı SDK'larla iletişimin nasıl yönetileceği gösterilmektedir:
// Get AppOwnedSdkSandboxInterface
List<AppOwnedSdkSandboxInterface> appOwnedSdks = mSdkContext
.getSystemService(SdkSandboxController.class)
.getAppOwnedSdkSandboxInterfaces();
AppOwnedSdkSandboxInterface appOwnedSdk = appOwnedSdks.stream()
.filter(s -> s.getName().contains(APP_OWNED_SDK_NAME))
.findAny()
.get();
IAppOwnedSdkApi appOwnedSdkApi =
IAppOwnedSdkApi.Stub.asInterface(appOwnedSdk.getInterface());
message = appOwnedSdkApi.getMessage();
Çalışma zamanının etkin olmadığı reklam SDK'ları kendilerini kaydedemeyeceğinden, kayıt işlemini gerçekleştiren ve iş ortağı veya uygulama SDK'larını doğrudan bağımlılıklar olarak dahil eden bir arabulucu SDK'sının oluşturulmasını öneririz. Bu aracı SDK'sı, çalışma zamanının etkin olmadığı SDK'lar ve bağımlılıklar ile bağdaştırıcı görevi gören çalışma zamanı özellikli arabulucu arasında iletişim kurar.
Etkinlik desteği
Çalışma zamanının etkin olduğu SDK'lar, manifest dosyalarına etkinlik etiketi ekleyemez ve kendi etkinliklerini doğrudan başlatamaz. Bir SdkSandboxActivityHandler
kaydedilip korumalı alan etkinliği başlatılarak Activity
nesnesine erişim sağlanır:
1. SdkSandboxActivityHandler kaydı yapma
SdkSandboxController#registerSdkSandboxActivityHandler(SandboxedActivityHandler)
kullanarak SdkSandboxActivityHandler
örneği kaydedin
API, bu nesneyi kaydeder ve geçirilen SdkSandboxActivityHandler
öğesini tanımlayan bir IBinder
nesnesi döndürür.
public interface SdkSandboxActivityHandler {
void onActivityCreated(Activity activity);
}
API, bu nesneyi kaydeder ve geçirilen SdkSandboxActivityHandler
öğesini tanımlayan bir IBinder
nesnesi döndürür.
2. Korumalı Alan etkinliğini başlatma
SDK, kayıtlı SdkSandboxActivityHandler
öğesini tanımlamak için döndürülen jetonu istemci uygulamasına iletir. İstemci uygulaması daha sonra SdkSandboxManager#startSdkSandboxActivity(Activity, Binder)
yöntemini çağırarak Korumalı Alan'ı başlatmak için bir etkinlik ile birlikte kayıtlı SdkSandboxActivityHandler
öğesini tanımlayan bir jeton iletir.
Bu adım, istekte bulunan SDK ile aynı SDK Çalışma Zamanında çalışan yeni bir platform etkinliği başlatır.
Etkinlik başladığında SDK, Activity#OnCreate(Bundle)
yürütme işleminin parçası olarak SdkSandboxActivityHandler#onActivityCreated(Activity)
çağrısıyla bilgilendirilir.
Örneğin, Activity
nesnesine erişimi olan ve arayan, Activity#setContentView(View)
yöntemini çağırarak contentView
için bir görünüm ayarlayabilir.
Yaşam döngüsü geri çağırmalarını kaydetmek için Activity#registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks)
kullanın.
OnBackInvokedCallback
öğesini iletilen etkinliğe kaydetmek için Activity#getOnBackInvokedDispatcher().registerOnBackInvokedCallback(Int,
OnBackInvokedCallback)
kodunu kullanın.
SDK Çalışma Zamanında video oynatıcıları test etme
Özel Korumalı Alan, banner reklamları desteklemenin yanı sıra SDK Çalışma Zamanı içinde çalışan video oynatıcıları da destekler.
Video oynatıcıları test etme akışı, banner reklamların test edilmesine benzer. SDK'nızın giriş noktasındaki getView()
yöntemini, döndürülen View
nesnesine video oynatıcı içerecek şekilde değiştirin. Özel Korumalı Alan tarafından desteklenmesini beklediğiniz tüm video oynatıcı akışlarını test edin. SDK ile istemci uygulaması arasında videonun yaşam döngüsüyle ilgili iletişimin kapsam dışında olduğunu unutmayın. Bu nedenle, bu işlev için henüz geri bildirim gerekli değildir.
Testleriniz ve geri bildirimleriniz SDK Çalışma Zamanı'nın tercih ettiğiniz video oynatıcının tüm kullanım alanlarını desteklemesini sağlar.
Aşağıdaki kod snippet'i, URL'den yüklenen basit bir video görünümünün nasıl döndürüleceğini gösterir.
Kotlin
class SdkProviderImpl : SandboxedSdkProvider() { override fun getView(windowContext: Context, bundle: Bundle, width: Int, height: Int): View { val videoView = VideoView(windowContext) val layoutParams = LinearLayout.LayoutParams(width, height) videoView.setLayoutParams(layoutParams) videoView.setVideoURI(Uri.parse("https://test.website/video.mp4")) videoView.setOnPreparedListener { mp -> mp.start() } return videoView } }
Java
public class SdkProviderImpl extends SandboxedSdkProvider { @Override public View getView(Context windowContext, Bundle bundle, int width, int height) { VideoView videoView = new VideoView(windowContext); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(width, height); videoView.setLayoutParams(layoutParams); videoView.setVideoURI(Uri.parse("https://test.website/video.mp4")); videoView.setOnPreparedListener(mp -> { mp.start(); }); return videoView; } }
SDK'nızda depolama API'lerini kullanma
SDK Çalışma Zamanı'ndaki SDK'lar artık bir uygulamanın dahili depolama alanına erişemez, bu verileri okuyamaz veya yazamaz. Bunun tersi de geçerlidir. SDK Çalışma Zamanı, uygulamadan ayrı olması garanti edilen kendi dahili depolama alanına ayrılır.
SDK'lar, SandboxedSdkProvider#getContext()
tarafından döndürülen Context
nesnesindeki dosya depolama API'lerini kullanarak bu ayrı dahili depolama alanına erişebilir. SDK'lar yalnızca dahili depolama alanını kullanabilir. Bu nedenle, yalnızca Context.getFilesDir()
veya Context.getCacheDir()
gibi dahili depolama API'leri çalışır. Dahili depolama alanından erişim bölümünde daha fazla örnek bulabilirsiniz.
SDK Çalışma Zamanı'ndan harici depolama alanına erişim desteklenmez. Harici depolama alanına erişmek için API'lerin çağrılması bir istisnaya neden olur veya null
hatası döndürür. Birkaç örnek:
- Dosyalara Depolama Erişim Çerçevesi'ni kullanarak erişmek
SecurityException
hatası verir. getExternalFilsDir()
işlevi her zamannull
değerini döndürür.
Android 13'te SDK Çalışma Zamanı'ndaki tüm SDK'lar, SDK Çalışma Zamanı için ayrılan dahili depolama alanını paylaşır. Depolama alanı, istemci uygulaması kaldırılana veya istemci uygulama verileri temizlenene kadar korunur.
Depolama alanı için SandboxedSdkProvider.getContext()
tarafından iade edilen Context
paketini kullanmanız gerekir. Dosya depolama API'sinin uygulama bağlamı gibi başka bir Context
nesne örneğinde kullanılması, her durumda veya gelecekte beklendiği gibi çalışacağı garanti edilmez.
Aşağıdaki kod snippet'i, SDK Çalışma Zamanı'nda depolama alanının nasıl kullanılacağını gösterir:
Kotlin
private static class SdkInterfaceStorage extends ISdkInterface.Stub { override fun doSomething() { val filename = "myfile" val fileContents = "content" try { getContext().openFileOutput(filename, Context.MODE_PRIVATE).use { it.write(fileContents.toByteArray()) } catch (e: Exception) { throw RuntimeException(e) } } } }
Java
private static class SdkInterfaceStorage extends ISdkInterface.Stub { @Override public void doSomething() { final filename = "myFile"; final String fileContents = "content"; try (FileOutputStream fos = getContext().openFileOutput(filename, Context.MODE_PRIVATE)) { fos.write(fileContents.toByteArray()); } catch (Exception e) { throw new RuntimeException(e); } } }
SDK başına depolama
Her SDK Çalışma Zamanı için ayrı dahili depolamada, her SDK'nın kendi depolama dizini bulunur. SDK başına depolama, SDK Çalışma Zamanı'nın dahili depolamasının mantıksal bir ayrımıdır. Her SDK'nın kullandığı depolama alanı miktarını hesaplamaya yardımcı olur.
Android 13'te yalnızca bir API, SDK başına depolamaya yol döndürür:
Context#getDataDir()
.
Android 14'te, Context
nesnesindeki tüm dahili depolama API'leri her SDK için bir depolama yolu döndürür. Aşağıdaki adb komutunu çalıştırarak bu özelliği etkinleştirmeniz gerekebilir:
adb shell device_config put adservices sdksandbox_customized_sdk_context_enabled true
Müşterinin SharedPreferences
cihazı okunuyor
İstemci uygulamaları, SharedPreferences
cihazından bir anahtar kümesini SdkSandbox
ile paylaşmayı seçebilir. SDK'lar, SdkSanboxController#getClientSharedPreferences()
API'yi kullanarak istemci uygulamasından senkronize edilen verileri okuyabilir. Bu API'nin döndürdüğü SharedPreferences
yalnızca okuma amaçlıdır. Bu e-postaya yazmamalısınız.
Google Play Hizmetleri tarafından sağlanan reklam kimliğine erişme
SDK'nızın Google Play Hizmetleri tarafından sağlanan reklam kimliğine erişmesi gerekiyorsa:
- SDK'nın manifest dosyasında
android.permission.ACCESS_ADSERVICES_AD_ID
iznini beyan edin. - Değeri eşzamansız olarak almak için
AdIdManager#getAdId()
değerini kullanın.
Google Play Hizmetleri tarafından sağlanan uygulama grubu kimliğine erişme
SDK'nızın, Google Play Hizmetleri tarafından sağlanan uygulama grubu kimliğine erişmesi gerekiyorsa:
- Değeri eşzamansız olarak almak için
AppSetIdManager#getAppSetId()
değerini kullanın.
İstemci uygulamalarını güncelleme
SDK Çalışma Zamanında çalışan bir SDK'ya çağrı yapmak için çağrı yapan istemci uygulamasında aşağıdaki değişiklikleri yapın:
INTERNET
veACCESS_NETWORK_STATE
izinlerini uygulamanızın manifest dosyasına ekleyin:<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Uygulamanızın reklam içeren etkinliğinde
SdkSandboxManager
referansı, SDK'nın yüklenip yüklenmediğini öğrenmek için bir boole ve uzaktan oluşturma için birSurfaceView
nesnesi tanımlayın:Kotlin
private lateinit var mSdkSandboxManager: SdkSandboxManager private lateinit var mClientView: SurfaceView private var mSdkLoaded = false companion object { private const val SDK_NAME = "com.example.privacysandbox.provider" }
Java
private static final String SDK_NAME = "com.example.privacysandbox.provider"; private SdkSandboxManager mSdkSandboxManager; private SurfaceView mClientView; private boolean mSdkLoaded = false;
SDK Çalışma Zamanı işleminin cihazda kullanılıp kullanılamadığını kontrol edin.
SdkSandboxState
sabitini (getSdkSandboxState()
) kontrol edin.SDK_SANDBOX_STATE_ENABLED_PROCESS_ISOLATION
, SDK Çalışma Zamanı'nın kullanılabilir olduğu anlamına gelir.loadSdk()
aramasının başarılı olup olmadığını kontrol edin. İstisna atlanmadığında başarılı sayılır ve alıcı daSandboxedSdk
örneği olduğunda başarılı olur.Ön planda
loadSdk()
çağırın. Arka plandan çağrılırsa birSecurityException
atılır.LoadSdkException
atılıp atılmadığını doğrulamak içinOutcomeReceiver
öğesindeSandboxedSdk
örneği olup olmadığını kontrol edin. SDK Çalışma Zamanı'nın kullanılamayabileceğini belirten bir istisna vardır.
SdkSandboxState
veyaloadSdk
çağrısı başarısız olursa SDK Çalışma Zamanı kullanılamaz ve çağrı, mevcut SDK'ya geri dönmelidir.SDK yüklendikten sonra çalışma zamanında SDK ile etkileşimde bulunmak için
OutcomeReceiver
uygulayarak bir geri çağırma sınıfı tanımlayın. Aşağıdaki örnekte istemci, SDK'nın başarıyla yüklenmesini beklemek için geri çağırmayı kullanır ve ardından SDK'dan bir web görünümü oluşturmayı dener. Geri çağırmalar bu adımın ilerleyen kısımlarında tanımlanır.Kotlin
private inner class LoadSdkOutcomeReceiverImpl private constructor() : OutcomeReceiver
{ override fun onResult(sandboxedSdk: SandboxedSdk) { mSdkLoaded = true val binder: IBinder = sandboxedSdk.getInterface() if (!binderInterface.isPresent()) { // SDK is not loaded anymore. return } val sdkInterface: ISdkInterface = ISdkInterface.Stub.asInterface(binder) sdkInterface.doSomething() Handler(Looper.getMainLooper()).post { val bundle = Bundle() bundle.putInt(SdkSandboxManager.EXTRA_WIDTH_IN_PIXELS, mClientView.getWidth()) bundle.putInt(SdkSandboxManager.EXTRA_HEIGHT_IN_PIXELS, mClientView.getHeight()) bundle.putInt(SdkSandboxManager.EXTRA_DISPLAY_ID, display!!.displayId) bundle.putInt(SdkSandboxManager.EXTRA_HOST_TOKEN, mClientView.getHostToken()) mSdkSandboxManager!!.requestSurfacePackage( SDK_NAME, bundle, { obj: Runnable -> obj.run() }, RequestSurfacePackageOutcomeReceiverImpl()) } } override fun onError(error: LoadSdkException) { // Log or show error. } } Java
import static android.app.sdksandbox.SdkSandboxManager.EXTRA_DISPLAY_ID; import static android.app.sdksandbox.SdkSandboxManager.EXTRA_HEIGHT_IN_PIXELS; import static android.app.sdksandbox.SdkSandboxManager.EXTRA_HOST_TOKEN; import static android.app.sdksandbox.SdkSandboxManager.EXTRA_WIDTH_IN_PIXELS; private class LoadSdkOutcomeReceiverImpl implements OutcomeReceiver
{ private LoadSdkOutcomeReceiverImpl() {} @Override public void onResult(@NonNull SandboxedSdk sandboxedSdk) { mSdkLoaded = true; IBinder binder = sandboxedSdk.getInterface(); if (!binderInterface.isPresent()) { // SDK is not loaded anymore. return; } ISdkInterface sdkInterface = ISdkInterface.Stub.asInterface(binder); sdkInterface.doSomething(); new Handler(Looper.getMainLooper()).post(() -> { Bundle bundle = new Bundle(); bundle.putInt(EXTRA_WIDTH_IN_PIXELS, mClientView.getWidth()); bundle.putInt(EXTRA_HEIGHT_IN_PIXELS, mClientView.getHeight()); bundle.putInt(EXTRA_DISPLAY_ID, getDisplay().getDisplayId()); bundle.putInt(EXTRA_HOST_TOKEN, mClientView.getHostToken()); mSdkSandboxManager.requestSurfacePackage( SDK_NAME, bundle, Runnable::run, new RequestSurfacePackageOutcomeReceiverImpl()); }); } @Override public void onError(@NonNull LoadSdkException error) { // Log or show error. } } requestSurfacePackage()
çağrısı yaparken çalışma zamanında SDK'dan uzak bir görünüm geri almak içinOutcomeReceiver<Bundle, RequestSurfacePackageException>
arayüzünü uygulayın:Kotlin
private inner class RequestSurfacePackageOutcomeReceiverImpl : OutcomeReceiver
{ fun onResult(@NonNull result: Bundle) { Handler(Looper.getMainLooper()) .post { val surfacePackage: SurfacePackage = result.getParcelable( EXTRA_SURFACE_PACKAGE, SurfacePackage::class.java) mRenderedView.setChildSurfacePackage(surfacePackage) mRenderedView.setVisibility(View.VISIBLE) } } fun onError(@NonNull error: RequestSurfacePackageException?) { // Error handling } } Java
import static android.app.sdksandbox.SdkSandboxManager.EXTRA_SURFACE_PACKAGE; private class RequestSurfacePackageOutcomeReceiverImpl implements OutcomeReceiver
{ @Override public void onResult(@NonNull Bundle result) { new Handler(Looper.getMainLooper()) .post( () -> { SurfacePackage surfacePackage = result.getParcelable( EXTRA_SURFACE_PACKAGE, SurfacePackage.class); mRenderedView.setChildSurfacePackage(surfacePackage); mRenderedView.setVisibility(View.VISIBLE); }); } @Override public void onError(@NonNull RequestSurfacePackageException error) { // Error handling } } Görünümü göstermeyi tamamladığınızda,
SurfacePackage
işlevini bırakmak için şu numarayı aramayı unutmayın:surfacePackage.notifyDetachedFromWindow()
onCreate()
ürünündeSdkSandboxManager
ve gerekli geri çağırmaları başlatın, ardından SDK'yı yüklemek için istekte bulunun:Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mSdkSandboxManager = applicationContext.getSystemService( SdkSandboxManager::class.java ) mClientView = findViewById(R.id.rendered_view) mClientView.setZOrderOnTop(true) val loadSdkCallback = LoadSdkCallbackImpl() mSdkSandboxManager.loadSdk( SDK_NAME, Bundle(), { obj: Runnable -> obj.run() }, loadSdkCallback ) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSdkSandboxManager = getApplicationContext().getSystemService( SdkSandboxManager.class); mClientView = findViewById(R.id.rendered_view); mClientView.setZOrderOnTop(true); LoadSdkCallbackImpl loadSdkCallback = new LoadSdkCallbackImpl(); mSdkSandboxManager.loadSdk( SDK_NAME, new Bundle(), Runnable::run, loadSdkCallback); }
Uygulama, varsayılan
SharedPreferences
öğesinin belirli anahtarlarını Korumalı Alan ile paylaşmayı seçebilir. Bunu, herhangi birSdkSandbox
yöneticisi örneğindeSdkSandboxManager#addSyncedSharedPreferencesKeys(Set<String>keys)
yöntemini çağırarak yapabilirler. Uygulama hangi anahtarların senkronize edileceğiniSdkSandboxManager
'e bildirdikten sonra,SdkSandboxManager
bu anahtarların değerlerini korumalı alan ve SDK'lar ile senkronize eder ve ardındanSdkSandboxController#getClientSharedPreferences
kullanarak bunları okuyabilir. Daha fazla bilgi edinmek için Reading Client's SharedPreferences'a göz atın.Senkronize edilen anahtar grubu, uygulama yeniden başlatılırken korunmaz ve korumalı alanla senkronize edilen veriler, korumalı alan yeniden başlatıldığında silinir. Bu nedenle, uygulamanın her başlatıldığında
addSyncedSharedPreferencesKeys
yöntemini çağırarak senkronizasyonu başlatması çok önemlidir.Anahtarları kaldırmak için
SdkSandboxManager#removeSyncedSharedPreferencesKeys(Set<String>keys)
komutunu çağırarak senkronize edilen anahtar grubunda değişiklik yapabilirsiniz. Senkronize edilmekte olan geçerli anahtar grubunu görmek içinSdkSandboxManager#getSyncedSharedPreferencesKeys()
işlevini kullanın.Tuş grubunu mümkün olduğunca küçük tutmanızı ve yalnızca gerektiğinde kullanmanızı öneririz. SDK'lara genel amaçlı bilgi aktarmak istiyorsanız lütfen
SandboxedSdk
arayüzlerini kullanarak doğrudan SDK ile iletişim kurun. Bu API'leri kullanmak için olası bir senaryo, uygulamada Kullanıcı Rızası Yönetim Platformu (CMP) SDK'sı kullanılıyorsa korumalı alandaki SDK'ların varsayılan olarakSharedPreferences
CMP SDK depoladığı verileri okumak istemesidir.Kotlin
override fun onCreate(savedInstanceState: Bundle?) { … // At some point, initiate the set of keys for synchronization with sandbox mSdkSandboxManager.addSyncedSharedPreferencesKeys(Set.of("foo", "bar")); }
Java
@Override protected void onCreate(Bundle savedInstanceState) { … // At some point, initiate the set of keys for synchronization with sandbox mSdkSandboxManager.addSyncedSharedPreferencesKeys(Set.of("foo", "bar")); }
SDK korumalı alanı işleminin beklenmedik bir şekilde sona erdiği durumların üstesinden gelmek amacıyla
SdkSandboxProcessDeathCallback
arayüzü için bir uygulama tanımlayın:Kotlin
private inner class SdkSandboxLifecycleCallbackImpl() : SdkSandboxProcessDeathCallback { override fun onSdkSandboxDied() { // The SDK runtime process has terminated. To bring back up the // sandbox and continue using SDKs, load the SDKs again. val loadSdkCallback = LoadSdkOutcomeReceiverImpl() mSdkSandboxManager.loadSdk( SDK_NAME, Bundle(), { obj: Runnable -> obj.run() }, loadSdkCallback) } }
Java
private class SdkSandboxLifecycleCallbackImpl implements SdkSandboxProcessDeathCallback { @Override public void onSdkSandboxDied() { // The SDK runtime process has terminated. To bring back up // the sandbox and continue using SDKs, load the SDKs again. LoadSdkOutcomeReceiverImpl loadSdkCallback = new LoadSdkOutcomeReceiverImpl(); mSdkSandboxManager.loadSdk( SDK_NAME, new Bundle(), Runnable::run, loadSdkCallback); } }
SDK korumalı alanının ne zaman sonlandırıldığı hakkında bilgi almak üzere bu geri çağırmayı kaydetmek için istediğiniz zaman aşağıdaki satırı ekleyin:
Kotlin
mSdkSandboxManager.addSdkSandboxProcessDeathCallback({ obj: Runnable -> obj.run() }, SdkSandboxLifecycleCallbackImpl())
Java
mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, new SdkSandboxLifecycleCallbackImpl());
İşlemi sona erdiğinde korumalı alanın durumu kaybolduğundan, SDK tarafından uzaktan oluşturulan görünümler artık düzgün çalışmayabilir. SDK'larla etkileşimde bulunmaya devam etmek için bu görünümlerin, yeni bir korumalı alan işlemi başlatılmak üzere tekrar yüklenmesi gerekir.
SDK modülünüz için istemci uygulamanızın
build.gradle
öğesine bağımlılık ekleyin:dependencies { ... implementation project(':<your-sdk-module>') ... }
Uygulamalarınızı test etme
İstemci uygulamanızı çalıştırmak için Android Studio veya komut satırını kullanarak SDK uygulamasını ve istemci uygulamasını test cihazınıza yükleyin.
Android Studio aracılığıyla dağıtma
Android Studio üzerinden dağıtım yaparken aşağıdaki adımları tamamlayın:
- İstemci uygulamanızın Android Studio projesini açın.
- Çalıştır > Yapılandırmaları Düzenle'ye gidin. Çalıştırma/Hata Ayıklama Yapılandırması penceresi görüntülenir.
- Başlatma Seçenekleri'nin altında, Başlat'ı Belirtilen Etkinlik olarak ayarlayın.
- Etkinlik'in yanındaki üç nokta menüsünü tıklayın ve istemciniz için Ana Etkinlik'i seçin.
- Uygula'yı ve ardından Tamam'ı tıklayın.
- İstemci uygulamasını ve SDK'yı test cihazınıza yüklemek için Çalıştır'ı
tıklayın.
Komut satırında dağıt
Komut satırını kullanarak dağıtım yaparken aşağıdaki listede yer alan adımları tamamlayın.
Bu bölümde SDK uygulama modülünüzün sdk-app
, istemci uygulama modülünüzün ise client-app
olduğu varsayılmıştır.
Bir komut satırı terminalinden Privacy Sandbox SDK APK'larını oluşturun:
./gradlew :client-app:buildPrivacySandboxSdkApksForDebug
Bu komut, oluşturulan APK'lar için konum bilgisini verir. Bu APK'lar yerel hata ayıklama anahtarınızla imzalanır. Bir sonraki komutta bu yola ihtiyacınız olacaktır.
APK'yı cihazınıza yükleyin:
adb install -t /path/to/your/standalone.apk
Android Studio'da, Çalıştır > Yapılandırmaları Düzenle'yi tıklayın. Run/Debug Configuration (Yapılandırmayı Çalıştırma/Hata Ayıklama) penceresi görünür.
Yükleme Seçenekleri altında, Dağıt'ı Varsayılan APK olarak ayarlayın.
Uygula'yı ve ardından Tamam'ı tıklayın.
APK paketini test cihazınıza yüklemek için Çalıştır'ı tıklayın.
Uygulamalarınızda hata ayıklama
İstemci uygulamasında hata ayıklamak için Android Studio'da Hata Ayıkla
düğmesini tıklayın.
SDK uygulamasındaki hataları ayıklamak için Çalıştır > İşleme Ekle'ye gidin. Bu ekranda açılan pop-up ekranı (aşağıda gösterilmiştir). Tüm işlemleri göster kutusunu işaretleyin. Görüntülenen listede CLIENT_APP_PROCESS_sdk_sandbox
adlı işlemi arayın. SDK'nızda hata ayıklamaya başlamak için bu seçeneği belirleyin ve SDK uygulamasının koduna ayrılma noktaları ekleyin.
![SDK uygulama işlemi, iletişim kutusunun alt kısmına yakın bir yerdeki liste görünümünde gösterilir](https://developers-dot-devsite-v2-prod.appspot.com/static/privacy-sandbox/assets/images/android/debug-sdk-app.png?authuser=5&hl=tr)
SDK çalışma zamanını komut satırından başlatma ve durdurma
Uygulamanızın SDK çalışma zamanı sürecini başlatmak için aşağıdaki kabuk komutunu kullanın:
adb shell cmd sdk_sandbox start [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>
Benzer şekilde, SDK çalışma zamanı işlemini durdurmak için şu komutu çalıştırın:
adb shell cmd sdk_sandbox stop [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>
Şu anda hangi SDK'ların yüklü olduğunu kontrol etme
SdkSandboxManager
içindeki getSandboxedSdks
işlevini kullanarak şu anda hangi SDK'ların yüklenmiş olduğunu kontrol edebilirsiniz.
Sınırlamalar
SDK Çalışma Zamanı için devam etmekte olan özelliklerin listesi için sürüm notlarına göz atın.
Kod örnekleri
GitHub'daki SDK Çalışma Zamanı ve Gizliliği Koruma API'leri Deposu, başlamanıza yardımcı olacak bir dizi bağımsız Android Studio projesi içerir. Buna, SDK Çalışma Zamanı'nı nasıl başlatacağınızı ve çağıracağınızı gösteren örnekler de dahildir.Hataları ve sorunları bildirme
Geri bildirimleriniz, Android'deki Özel Korumalı Alan için çok önemlidir. Android'de Özel Korumalı Alan'ın iyileştirilmesiyle ilgili sorunları veya fikirlerinizi bizimle paylaşabilirsiniz.
Sizin için önerilenler
- Not: Bağlantı metni JavaScript kapalıyken görüntülenir
- SDK Çalışma Zamanı
- Sürüm notları
- Android'de Protected Audience API geliştirici kılavuzu