Panduan developer Runtime SDK

Saat Anda membaca dokumentasi Privacy Sandbox di Android, gunakan tombol Pratinjau Developer atau Beta untuk memilih versi program yang sedang Anda gunakan, karena petunjuknya dapat bervariasi.


Berikan masukan

Runtime SDK memungkinkan SDK berjalan di sandbox khusus yang terpisah dari aplikasi pemanggil. Runtime SDK memberikan peningkatan pengamanan dan jaminan seputar pengumpulan data pengguna. Hal ini dilakukan melalui lingkungan eksekusi yang dimodifikasi, yang membatasi hak akses data dan serangkaian izin yang diperbolehkan. Pelajari lebih lanjut Runtime SDK di proposal desain.

Langkah-langkah di halaman ini akan memandu Anda dalam proses pembuatan SDK yang mendukung runtime yang menentukan tampilan berbasis web yang dapat dirender dari jarak jauh ke aplikasi panggilan.

Batasan umum

Untuk daftar kemampuan yang sedang berlangsung untuk Runtime SDK, lihat catatan rilis.

Batasan berikut diperkirakan akan diperbaiki dalam rilis platform Android utama berikutnya.

  • Rendering iklan dalam tampilan yang dapat di-scroll. Misalnya, RecyclerView tidak berfungsi dengan baik.
    • Anda mungkin mengalami jank saat mengubah ukuran.
    • Peristiwa scroll sentuh pengguna tidak diteruskan ke runtime dengan benar.
  • Storage API

Masalah berikut akan diperbaiki pada 2023:

  • API getAdId dan getAppSetId belum berfungsi dengan baik karena dukungan untuk API ini belum diaktifkan.

Sebelum memulai

Sebelum memulai, selesaikan langkah-langkah berikut:

  1. Menyiapkan lingkungan pengembangan Anda untuk Privacy Sandbox di Android. Alat untuk mendukung Runtime SDK sedang dalam pengembangan aktif sehingga panduan ini akan mengharuskan Anda menggunakan Android Studio versi Canary terbaru. Anda dapat menjalankan versi Android Studio ini secara paralel dengan versi lain yang Anda gunakan. Jadi, beri tahu kami jika persyaratan ini tidak berhasil untuk Anda.

  2. Instal image sistem ke perangkat yang didukung atau siapkan emulator yang menyertakan dukungan untuk Privacy Sandbox di Android.

Menyiapkan project di Android Studio

Untuk mencoba Runtime SDK, gunakan model yang mirip dengan model klien-server. Perbedaan utamanya adalah aplikasi (klien) dan SDK ("server") berjalan di perangkat yang sama.

  1. Tambahkan modul aplikasi ke project Anda. Modul ini berfungsi sebagai klien yang mendorong SDK.
  2. Dalam modul aplikasi, aktifkan Runtime SDK, deklarasikan izin yang diperlukan, dan konfigurasi layanan iklan khusus API.
  3. Tambahkan satu modul library ke project Anda. Modul ini berisi kode SDK Anda.
  4. Dalam modul SDK, deklarasikan izin yang diperlukan. Anda tidak perlu mengonfigurasi layanan iklan khusus API dalam modul ini.
  5. Hapus dependencies di file build.gradle modul library yang tidak digunakan SDK Anda. Dalam sebagian besar kasus, Anda dapat menghapus semua dependensi. Anda dapat melakukannya dengan membuat direktori baru yang namanya sesuai dengan SDK Anda.
  6. Buat modul baru menggunakan jenis com.android.privacy-sandbox-sdk secara manual. Modul ini disertakan dengan kode SDK untuk membuat APK yang dapat di-deploy ke perangkat. Anda dapat melakukannya dengan membuat direktori baru yang namanya sesuai dengan SDK Anda. Tambahkan file build.gradle kosong. Konten file ini akan diisi nanti dalam panduan ini.

  7. Tambahkan cuplikan berikut ke file gradle.properties Anda:

    android.experimental.privacysandboxsdk.enable=true
    
  8. Download image emulator TiramisuPrivacySandbox, lalu buat emulator dengan image ini yang menyertakan Play Store.

Bergantung pada apakah Anda seorang developer SDK atau developer aplikasi, Anda mungkin memiliki penyiapan akhir yang berbeda dari yang dijelaskan dalam paragraf sebelumnya.

Instal SDK ke perangkat pengujian, sama dengan cara Anda menginstal aplikasi, menggunakan Android Studio atau Android Debug Bridge (ADB). Untuk membantu Anda memulai, kami telah membuat aplikasi contoh dalam bahasa pemrograman Kotlin dan Java yang dapat ditemukan di repositori GitHub ini. File README dan manifes memiliki komentar yang menjelaskan apa yang harus diubah untuk menjalankan contoh dalam versi stabil Android Studio.

Menyiapkan SDK

  1. Buat direktori level modul secara manual. Direktori ini berfungsi sebagai wrapper terkait kode penerapan Anda untuk mem-build APK SDK. Di direktori baru, tambahkan file build.gradle dan isi dengan cuplikan berikut. Gunakan nama unik untuk SDK yang mendukung runtime (RE-SDK), dan berikan versi. Sertakan modul library Anda di bagian dependencies.

    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>')
    }
    
  2. Buat class di library penerapan Anda sebagai titik entri untuk SDK Anda. Nama class harus dipetakan ke nilai sdkProviderClassName dan memperluas SandboxedSdkProvider.

Titik entri untuk SDK Anda memperluas SandboxedSdkProvider. SandboxedSdkProvider berisi objek Context untuk SDK Anda, yang dapat diakses dengan memanggil getContext(). Konteks ini hanya boleh diakses setelah onLoadSdk() dipanggil.

Agar aplikasi SDK dapat dikompilasi, Anda perlu mengganti metode untuk menangani siklus proses SDK:

onLoadSdk()

Memuat SDK di sandbox, dan memberi tahu aplikasi panggilan saat SDK siap menangani permintaan dengan meneruskan antarmukanya sebagai objek IBinder yang digabungkan di dalam objek SandboxedSdk baru. Panduan layanan terikat menyediakan berbagai cara untuk menyediakan IBinder. Anda memiliki fleksibilitas untuk memilih cara, tetapi harus konsisten untuk SDK dan aplikasi panggilan.

Dengan menggunakan AIDL sebagai contoh, Anda harus menentukan file AIDL untuk menampilkan IBinder yang akan dibagikan dan digunakan oleh aplikasi:

// ISdkInterface.aidl
interface ISdkInterface {
    // the public functions to share with the App.
    int doSomething();
}
getView()

Membuat dan menyiapkan tampilan untuk iklan Anda, melakukan inisialisasi tampilan dengan cara yang sama seperti tampilan Android lainnya, dan menampilkan tampilan yang akan dirender dari jarak jauh di jendela dengan lebar dan tinggi yang ditentukan dalam piksel.

Cuplikan kode berikut menunjukkan cara mengganti metode ini:

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 adalah wrapper layanan sistem berbasis konteks yang tersedia untuk SDK. Fungsi ini dapat diambil oleh SDK menggunakan konteks yang diterima dari SandboxedSdkProvider#getContext() dan memanggil context.getSystemService(SdkSandboxController.class) dalam konteks tersebut. Pengontrol memiliki API yang membantu SDK berinteraksi dengan dan mendapatkan informasi dari Privacy Sandbox.

Sebagian besar API di pengontrol akan menampilkan pengecualian jika SandboxedSdkContext bukan konteks yang digunakan untuk mengakses. Kami berencana untuk membuat wrapper layanan tidak tersedia untuk konteks lain. SdkSandboxController dimaksudkan untuk digunakan oleh penyedia SDK, dan tidak direkomendasikan untuk digunakan oleh developer aplikasi.

Komunikasi SDK ke SDK

SDK dalam runtime harus dapat berkomunikasi satu sama lain untuk mendukung mediasi dan kasus penggunaan terkait. Kumpulan alat yang dijelaskan di sini menyediakan antarmuka untuk digunakan dengan SDK yang tersedia bagi SDK lain dalam sandbox. Implementasi Runtime SDK ini adalah langkah pertama untuk mengaktifkan komunikasi SDK ke SDK, dan mungkin belum mencakup semua kasus penggunaan untuk mediasi di Privacy Sandbox.

getSandboxedSdks() API di SdkSandboxController menyediakan class SandboxedSdk untuk semua SDK yang dimuat di Privacy Sandbox. Objek SandboxedSdk memiliki detail tentang SDK dan sdkInterface agar klien dapat berkomunikasi dengannya.

SDK di Privacy Sandbox diperkirakan akan menggunakan cuplikan kode yang serupa dengan hal berikut ini untuk berkomunikasi dengan SDK lain. Asumsikan kode ini ditulis untuk mengaktifkan "SDK1" guna berkomunikasi dengan "SDK2", keduanya dimuat oleh aplikasi di Privacy Sandbox.

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);
}

Dalam contoh di atas, SDK1 menambahkan library AIDL SDK2 sebagai dependensi. SDK klien ini berisi kode Binder yang dihasilkan oleh AIDL. Kedua SDK harus mengekspor library AIDL ini. Hal ini identik dengan hal yang diperkirakan akan dilakukan saat aplikasi berkomunikasi dengan SDK di Privacy Sandbox.

Dukungan untuk cara yang dibuat secara otomatis untuk berbagi antarmuka antar-SDK akan ditambahkan dalam update mendatang.

SDK dalam runtime mungkin perlu berkomunikasi dengan dependensi aplikasi dan SDK iklan yang belum mengaktifkan runtime.

registerAppOwnedSdkSandboxInterface() API di SdkSandboxManager menyediakan cara bagi SDK yang tidak mengaktifkan runtime untuk mendaftarkan antarmukanya dengan platform. getAppOwnedSdkSandboxInterfaces() API di SdkSandboxController menyediakan AppOwnedSdkSandboxInterface untuk semua SDK yang terdaftar dan tertaut secara statis.

Contoh berikut mengilustrasikan cara mendaftarkan antarmuka agar tersedia untuk komunikasi SDK yang mendukung runtime:

// Register AppOwnedSdkSandboxInterface
mSdkSandboxManager.registerAppOwnedSdkSandboxInterface(
    new AppOwnedSdkSandboxInterface(
        APP_OWNED_SDK_NAME, (long) APP_OWNED_SDK_VERSION, new AppOwnedSdkApi())
    );

Contoh ini menunjukkan cara melengkapi komunikasi dengan SDK yang tidak mendukung runtime:

// 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();

Karena SDK iklan yang tidak mengaktifkan runtime mungkin tidak dapat mendaftar sendiri, kami mengusulkan pembuatan SDK mediator yang menangani pendaftaran dan menyertakan SDK partner atau aplikasi sebagai dependensi langsung. SDK mediator ini menciptakan komunikasi antara SDK dan dependensi yang tidak diaktifkan runtime dan mediator yang mendukung runtime yang bertindak sebagai adaptor.

Dukungan aktivitas

SDK yang mendukung runtime tidak dapat menambahkan tag aktivitas ke file manifesnya dan tidak dapat memulai aktivitasnya sendiri secara langsung. Akses diberikan ke objek Activity dengan mendaftarkan SdkSandboxActivityHandler dan memulai aktivitas sandbox:

1. Mendaftarkan SdkSandboxActivityHandler

Mendaftarkan instance SdkSandboxActivityHandler menggunakan SdkSandboxController#registerSdkSandboxActivityHandler(SandboxedActivityHandler)

API mendaftarkan objek tersebut dan menampilkan objek IBinder yang mengidentifikasi SdkSandboxActivityHandler yang diteruskan.

public interface SdkSandboxActivityHandler {
    void onActivityCreated(Activity activity);
}

API mendaftarkan objek tersebut dan menampilkan objek IBinder yang mengidentifikasi SdkSandboxActivityHandler yang diteruskan.

2. Memulai aktivitas Sandbox

SDK meneruskan token yang ditampilkan untuk mengidentifikasi SdkSandboxActivityHandler yang terdaftar ke aplikasi klien. Selanjutnya, aplikasi klien memanggil SdkSandboxManager#startSdkSandboxActivity(Activity, Binder), meneruskan aktivitas untuk memulai Sandbox, dan token yang mengidentifikasi SdkSandboxActivityHandler yang terdaftar.

Langkah ini memulai aktivitas platform baru yang berjalan di Runtime SDK yang sama dengan SDK permintaan.

Saat aktivitas dimulai, SDK akan diberi tahu melalui panggilan ke SdkSandboxActivityHandler#onActivityCreated(Activity) sebagai bagian dari eksekusi Activity#OnCreate(Bundle).

Misalnya, dengan akses ke objek Activity, dan pemanggil dapat menyetel tampilan contentView dengan memanggil Activity#setContentView(View).

Untuk mendaftarkan callback siklus proses, gunakan Activity#registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks).

Untuk mendaftarkan OnBackInvokedCallback ke aktivitas yang diteruskan, gunakan Activity#getOnBackInvokedDispatcher().registerOnBackInvokedCallback(Int, OnBackInvokedCallback).

Menguji pemutar video di Runtime SDK

Selain mendukung iklan banner, Privacy Sandbox berkomitmen untuk mendukung pemutar video yang berjalan di dalam Runtime SDK.

Alur untuk menguji pemutar video mirip dengan menguji iklan banner. Ubah metode getView() titik entri SDK Anda untuk menyertakan pemutar video dalam objek View yang ditampilkan. Uji semua alur pemutar video yang Anda harapkan akan didukung oleh Privacy Sandbox. Perlu diketahui bahwa komunikasi antara SDK dan aplikasi klien tentang siklus proses video saat ini berada di luar cakupan, sehingga masukan belum diperlukan untuk fungsi ini.

Pengujian dan masukan Anda akan memastikan bahwa Runtime SDK mendukung semua kasus penggunaan pemutar video pilihan Anda.

Cuplikan kode berikut menunjukkan cara menampilkan tampilan video sederhana yang dimuat dari URL.

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;
        }
    }

Menggunakan storage API di SDK Anda

SDK di Runtime SDK tidak dapat lagi mengakses, membaca, atau menulis di penyimpanan internal aplikasi, dan sebaliknya. Runtime SDK akan diberi alokasi area penyimpanan internalnya sendiri, yang dijamin terpisah dari aplikasi.

SDK akan dapat mengakses penyimpanan internal terpisah ini menggunakan API penyimpanan file pada objek Context yang ditampilkan oleh SandboxedSdkProvider#getContext(). SDK hanya dapat menggunakan penyimpanan internal sehingga hanya API penyimpanan internal, seperti Context.getFilesDir() atau Context.getCacheDir() yang akan berfungsi. Lihat contoh lainnya di Mengakses dari penyimpanan internal.

Akses ke penyimpanan eksternal dari Runtime SDK tidak didukung. Memanggil API untuk mengakses penyimpanan eksternal akan menampilkan pengecualian atau menampilkan null. Beberapa contoh:

Di Android 13, semua SDK di Runtime SDK akan membagikan penyimpanan internal yang dialokasikan untuk Runtime SDK. Penyimpanan akan dipertahankan sampai aplikasi klien di-uninstal, atau saat data aplikasi klien dihapus.

Anda harus menggunakan Context yang ditampilkan oleh SandboxedSdkProvider.getContext() untuk penyimpanan. Menggunakan API penyimpanan file pada instance objek Context lainnya, seperti konteks aplikasi, tidak dijamin akan berfungsi seperti yang diharapkan dalam semua situasi atau di masa mendatang.

Cuplikan kode berikut menunjukkan cara menggunakan penyimpanan di Runtime SDK:

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);
        }
    }

}

    

Penyimpanan per SDK

Dalam penyimpanan internal terpisah untuk setiap Runtime SDK, setiap SDK memiliki direktori penyimpanannya sendiri. Penyimpanan per SDK adalah pemisahan logis penyimpanan internal Runtime SDK yang membantu memperhitungkan jumlah penyimpanan yang digunakan setiap SDK.

Di Android 13, hanya satu API yang menampilkan jalur ke penyimpanan per SDK: Context#getDataDir().

Di Android 14, semua API penyimpanan internal pada objek Context menampilkan jalur penyimpanan untuk setiap SDK. Anda mungkin perlu mengaktifkan fitur ini dengan menjalankan perintah adb berikut:

adb shell device_config put adservices sdksandbox_customized_sdk_context_enabled true

Membaca SharedPreferences klien

Aplikasi klien dapat memilih untuk membagikan kumpulan kunci dari SharedPreferences-nya dengan SdkSandbox. SDK dapat membaca data yang disinkronkan dari aplikasi klien menggunakan SdkSanboxController#getClientSharedPreferences() API. SharedPreferences yang ditampilkan oleh API ini hanya untuk dibaca. Anda tidak boleh menulisnya.

Mengakses ID iklan yang disediakan oleh layanan Google Play

Jika SDK Anda memerlukan akses ke ID iklan yang disediakan oleh layanan Google Play:

  • Deklarasikan izin android.permission.ACCESS_ADSERVICES_AD_ID dalam manifes SDK.
  • Gunakan AdIdManager#getAdId() untuk mengambil nilai secara asinkron.

Mengakses ID kumpulan aplikasi yang disediakan oleh layanan Google Play

Jika SDK Anda memerlukan akses ke ID kumpulan aplikasi yang disediakan oleh layanan Google Play:

  • Gunakan AppSetIdManager#getAppSetId() untuk mengambil nilai secara asinkron.

Mengupdate aplikasi klien

Untuk memanggil SDK yang berjalan di Runtime SDK, terapkan perubahan berikut pada aplikasi klien yang melakukan panggilan:

  1. Tambahkan izin INTERNET dan ACCESS_NETWORK_STATE ke manifes aplikasi Anda:

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    
  2. Dalam aktivitas aplikasi Anda yang menyertakan iklan, deklarasikan referensi ke SdkSandboxManager, boolean untuk mengetahui apakah SDK telah dimuat, dan objek SurfaceView untuk rendering jarak jauh:

    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;
    
  3. Periksa apakah proses Runtime SDK tersedia di perangkat.

    1. Periksa konstanta SdkSandboxState (getSdkSandboxState()). SDK_SANDBOX_STATE_ENABLED_PROCESS_ISOLATION berarti Runtime SDK tersedia.

    2. Pastikan bahwa panggilan loadSdk() berhasil. Panggilan berhasil jika tidak ada pengecualian yang ditampilkan, dan penerima merupakan instance dari SandboxedSdk.

      • Panggil loadSdk() dari latar depan. Jika dipanggil dari latar belakang, SecurityException akan ditampilkan.

      • Periksa OutcomeReceiver untuk melihat instance SandboxedSdk guna memverifikasi apakah LoadSdkException ditampilkan. Pengecualian menunjukkan Runtime SDK mungkin tidak tersedia.

    Jika panggilan SdkSandboxState atau loadSdk gagal, Runtime SDK tidak tersedia dan panggilan harus dialihkan ke SDK yang ada.

  4. Tentukan class callback dengan menerapkan OutcomeReceiver untuk berinteraksi dengan SDK dalam runtime setelah dimuat. Pada contoh berikut, klien menggunakan callback untuk menunggu hingga SDK berhasil dimuat, lalu berupaya merender tampilan web dari SDK. Callback akan ditentukan nanti dalam langkah ini.

    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.
            }
        }
    

    Untuk mendapatkan kembali tampilan jarak jauh dari SDK dalam runtime saat memanggil requestSurfacePackage(), implementasikan antarmuka OutcomeReceiver<Bundle, RequestSurfacePackageException>:

    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
            }
        }
    

    Setelah selesai menunjukkan tampilan, jangan lupa merilis SurfacePackage dengan memanggil:

    surfacePackage.notifyDetachedFromWindow()
    
  5. Di onCreate(), lakukan inisialisasi SdkSandboxManager, callback yang diperlukan, lalu buat permintaan untuk memuat SDK:

    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);
    }
    
  6. Aplikasi dapat memilih untuk berbagi kunci tertentu dari SharedPreferences defaultnya dengan Sandbox. Mereka dapat melakukannya dengan memanggil metode SdkSandboxManager#addSyncedSharedPreferencesKeys(Set<String>keys) pada instance pengelola SdkSandbox mana pun. Setelah aplikasi memberi tahu SdkSandboxManager kunci mana yang akan disinkronkan, SdkSandboxManager akan menyinkronkan nilai kunci tersebut ke dalam sandbox dan SDK kemudian dapat membacanya menggunakan SdkSandboxController#getClientSharedPreferences. Lihat Membaca SharedPreferences Klien untuk mengetahui informasi selengkapnya.

    Kumpulan kunci yang disinkronkan tidak akan dipertahankan setiap kali aplikasi dimulai ulang dan data yang disinkronkan ke sandbox akan dihapus saat sandbox dimulai ulang. Oleh karena itu, aplikasi harus memulai sinkronisasi dengan memanggil addSyncedSharedPreferencesKeys setiap kali aplikasi dimulai.

    Anda dapat mengubah kumpulan kunci yang disinkronkan dengan memanggil SdkSandboxManager#removeSyncedSharedPreferencesKeys(Set<String>keys) untuk menghapus kunci. Untuk melihat kumpulan kunci saat ini yang sedang disinkronkan, gunakan SdkSandboxManager#getSyncedSharedPreferencesKeys().

    Sebaiknya buat kumpulan kunci sekecil mungkin dan gunakan hanya jika diperlukan. Jika Anda ingin meneruskan informasi ke SDK untuk tujuan umum, komunikasikan dengan SDK secara langsung menggunakan antarmuka SandboxedSdk mereka. Skenario yang memungkinkan untuk menggunakan API ini adalah jika aplikasi menggunakan SDK Consent Management Platform (CMP), SDK di dalam sandbox akan tertarik untuk membaca data yang disimpan di SDK CMP di SharedPreferences default.

    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"));
    }
    
    
  7. Untuk menangani kasus saat proses sandbox SDK tiba-tiba berhenti, tentukan implementasi untuk antarmuka SdkSandboxProcessDeathCallback:

    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);
              }
          }
    

    Untuk mendaftarkan callback ini guna menerima informasi tentang kapan sandbox SDK telah dihentikan, tambahkan baris berikut kapan saja:

    Kotlin

        mSdkSandboxManager.addSdkSandboxProcessDeathCallback({ obj: Runnable -> obj.run() },
                SdkSandboxLifecycleCallbackImpl())
    

    Java

        mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run,
                new SdkSandboxLifecycleCallbackImpl());
    

    Karena status sandbox hilang saat prosesnya dihentikan, tampilan yang telah dirender dari jarak jauh mungkin tidak lagi berfungsi dengan benar. Agar dapat terus berinteraksi dengan SDK, tampilan ini harus dimuat lagi sehingga proses sandbox baru dimulai.

  8. Tambahkan dependensi pada modul SDK ke build.gradle aplikasi klien Anda:

    dependencies {
        ...
        implementation project(':<your-sdk-module>')
        ...
    }

Menguji aplikasi Anda

Untuk menjalankan aplikasi klien, instal aplikasi SDK dan aplikasi klien ke perangkat pengujian Anda menggunakan Android Studio atau command line.

Men-deploy melalui Android Studio

Saat men-deploy melalui Android Studio, selesaikan langkah-langkah berikut:

  1. Buka project Android Studio untuk aplikasi klien Anda.
  2. Buka Run > Edit Configurations. Jendela Run/Debug Configuration akan muncul.
  3. Di bagian Launch Options, tetapkan Launch ke Specified Activity.
  4. Klik menu tiga titik di samping Activity dan pilih Main Activity untuk klien Anda.
  5. Klik Apply, lalu OK.
  6. Klik Run untuk menginstal aplikasi klien dan SDK di perangkat pengujian Anda.

Men-deploy pada command line

Saat men-deploy menggunakan command line, selesaikan langkah-langkah dalam daftar berikut. Bagian ini mengasumsikan bahwa nama modul aplikasi SDK Anda adalah sdk-app dan nama modul aplikasi klien Anda adalah client-app.

  1. Dari terminal command line, buat APK SDK Privacy Sandbox:

    ./gradlew :client-app:buildPrivacySandboxSdkApksForDebug
    

    Tindakan ini menghasilkan lokasi untuk APK yang dibuat. APK ini ditandatangani dengan kunci debug lokal Anda. Anda memerlukan jalur ini di perintah berikutnya.

  2. Instal APK di perangkat Anda:

    adb install -t /path/to/your/standalone.apk
    
  3. Di Android Studio, klik Run > Edit Configurations. Jendela Run/Debug Configuration akan muncul.

  4. Di bagian Installation Options, setel Deploy ke Default APK.

  5. Klik Apply, lalu OK.

  6. Klik Run untuk menginstal paket APK di perangkat pengujian Anda.

Men-debug aplikasi Anda

Untuk men-debug aplikasi klien, klik tombol Debug di Android Studio.

Untuk men-debug aplikasi SDK, buka Run > Attach to Process, yang menampilkan layar pop-up (ditampilkan di bawah). Centang kotak Tampilkan semua proses. Dalam daftar yang muncul, cari proses yang disebut CLIENT_APP_PROCESS_sdk_sandbox. Pilih opsi ini dan tambahkan titik henti sementara di kode aplikasi SDK untuk mulai men-debug SDK Anda.

Proses aplikasi SDK muncul dalam tampilan daftar di dekat bagian bawah
  dialog
Layar Choose process, tempat Anda dapat memilih aplikasi SDK untuk di-debug.

Memulai dan menghentikan runtime SDK dari command line

Untuk memulai proses runtime SDK untuk aplikasi Anda, gunakan perintah shell berikut:

adb shell cmd sdk_sandbox start [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>

Demikian pula, untuk menghentikan proses runtime SDK, jalankan perintah ini:

adb shell cmd sdk_sandbox stop [--user <USER_ID> | current] <CLIENT_APP_PACKAGE>

Memeriksa SDK yang saat ini dimuat

Anda dapat memeriksa SDK mana yang saat ini dimuat menggunakan fungsi getSandboxedSdks di dalam SdkSandboxManager.

Batasan

Untuk daftar kemampuan yang sedang berlangsung untuk Runtime SDK, lihat catatan rilis.

Contoh kode

Halaman Repositori Privacy Preserving API dan Runtime SDK di GitHub berisi kumpulan masing-masing project Android Studio untuk membantu Anda memulai, termasuk contoh yang menunjukkan cara menginisialisasi dan memanggil Runtime SDK.

Melaporkan bug dan masalah

Masukan Anda adalah bagian penting dari Privacy Sandbox di Android. Beri tahu kami jika Anda menemukan masalah atau memiliki ide untuk meningkatkan kualitas Privacy Sandbox di Android.