Panduan developer Runtime SDK

Berikan masukan

Runtime SDK memungkinkan SDK berjalan di sandbox khusus yang terpisah dari aplikasi panggilan. 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 Runtime SDK lebih lanjut 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.

Sebelum memulai

Sebelum memulai, selesaikan langkah-langkah berikut:

  1. Siapkan lingkungan pengembangan Anda untuk Privacy Sandbox di Android.
  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.

Tambahkan satu modul aplikasi dan satu modul SDK ke project Anda. Hal ini mempermudah untuk menjalankan dan menguji kode Anda secara berdampingan. Anda harus membuat dua aplikasi terpisah untuk memastikan bahwa kode aplikasi dan kode SDK terpisah.

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.

Menyiapkan SDK

Di file AndroidManifest.xml aplikasi SDK, sertakan elemen <sdk-library> dan <property> di bagian <application>, sebagaimana ditunjukkan dalam cuplikan kode berikut. Gunakan nama unik untuk SDK yang mendukung runtime dan berikan versi.

<application ...>
  <sdk-library android:name="com.example.privacysandbox.provider"
               android:versionMajor="1" />
  <property
        android:name="android.sdksandbox.PROPERTY_SDK_PROVIDER_CLASS_NAME"
        android:value="com.example.provider.SdkProviderImpl" />

</application>

Titik entri untuk SDK Anda memperluas SandboxedSdkProvider. Agar aplikasi SDK dapat dikompilasi, Anda perlu mengganti metode untuk menangani siklus proses SDK.

initSdk()
Menginisialisasi SDK, dan memberi tahu aplikasi panggilan saat inisialisasi selesai dan siap digunakan.
getView()
Membuat dan menyiapkan tampilan untuk iklan Anda, melakukan inisialisasi tampilan dengan cara yang sama seperti tampilan Android lainnya, dan menampilkan tampilan untuk rendering jarak jauh.
onDataReceived()
Menangani metadata yang dikirim dari aplikasi host menggunakan sendData().

Cuplikan kode berikut menunjukkan cara mengganti metode ini:

Kotlin

class SdkProviderImpl : SandboxedSdkProvider() {
    override fun initSdk(
        sandboxedSdkContext: SandboxedSdkContext, params: Bundle,
        executor: Executor, initSdkCallback: InitSdkCallback
    ) {
        // Update the callback with optional data to show that initialization
        // is complete.
        executor.execute { initSdkCallback.onInitSdkFinished(Bundle()) }
    }

    override fun getView(windowContext: Context, bundle: Bundle): View {
        val webView = WebView(windowContext)
        webView.loadUrl("https://developer.android.com/privacy-sandbox")
        return webView
    }

    override fun onDataReceived(bundle: Bundle, dataReceivedCallback: DataReceivedCallback) {
        // Update the callback with optional data to show that the receiving
        // or processing of data is complete
        dataReceivedCallback.onDataReceivedSuccess(Bundle())
    }
}

Java

public class SdkProviderImpl extends SandboxedSdkProvider {
    @Override
    public void initSdk(SandboxedSdkContext sandboxedSdkContext, Bundle params,
            Executor executor, InitSdkCallback initSdkCallback) {
        // Update the callback with optional data to show that the
        // initialization is complete.
        executor.execute(() -> initSdkCallback.onInitSdkFinished(new Bundle()));
    }

    @Override
    public View getView(Context windowContext, Bundle bundle) {
        WebView webView = new WebView(windowContext);
        webView.loadUrl("https://developer.android.com/privacy-sandbox");
        return webView;
    }

    @Override
    public void onDataReceived(Bundle bundle, DataReceivedCallback callback) {
        // Update the callback with optional data to show that the receiving or
        // processing of data is complete
        dataReceivedCallback.onDataReceivedSuccess(new Bundle());
    }
}

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 hal 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, params: Bundle): View {
        val videoView = VideoView(windowContext)
        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 params) {
        VideoView videoView = new VideoView(windowContext);
        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.

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

Setiap SDK dapat menggunakan penyimpanan per SDK-nya menggunakan API penyimpanan file pada objek SandboxedSdkContext yang diterima SDK dalam metode initSdk(). Penyimpanan per SDK akan dipertahankan sampai aplikasi klien di-uninstal, atau saat data aplikasi klien dihapus.

SDK hanya dapat menggunakan penyimpanan internal. Oleh karena itu, hanya API penyimpanan internal, seperti SandboxedSdkContext.getFilesDir() atau SandboxedSdkContext.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:

Anda harus menggunakan SandboxedSdkContext yang disediakan untuk penyimpanan. Menggunakan API penyimpanan file pada instance objek Context lainnya, seperti konteks aplikasi, tidak akan menggunakan penyimpanan internal per SDK dan tidak dijamin dapat berfungsi di semua situasi atau di masa mendatang.

Cuplikan kode berikut menunjukkan cara menggunakan penyimpanan di Runtime SDK:

Java

public class SdkProviderImpl extends SandboxedSdkProvider {
    private SandboxedSdkContext mContext;

    @Override
    public void initSdk(SandboxedSdkContext sandboxedSdkContext, Bundle params,
            Executor executor, InitSdkCallback initSdkCallback) {
        // Store reference to the SandboxedSdkContext for later usage
        mContext = sandboxedSdkContext;
    }

    @Override
    public void onDataReceived(Bundle data, DataReceivedCallback callback) {
        // Use the SandboxedSdkContext to use storage
        final filename = "extraData";
        final String fileContents = data.getString("extraData", "");
        try (FileOutputStream fos = mContext.openFileOutput(filename, Context.MODE_PRIVATE)) {
            fos.write(fileContents.toByteArray());
            callback.onDataReceivedSuccess();
        } catch (Exception e) {
            callback.onDataReceivedError("Unable to process data.");
        }
    }
}

Kotlin

class SdkProviderImpl : SandboxedSdkProvider() {
    private lateinit var mContext: SandboxedSdkContext

    override fun initSdk(
        sandboxedSdkContext: SandboxedSdkContext, params: Bundle,
        executor: Executor, initSdkCallback: InitSdkCallback
    ) {
        // Store reference to the SandboxedContext for later usage
        mContext = sandboxedSdkContext;
    }

    override fun onDataReceived(data: Bundle, callback: DataReceivedCallback) {
        // Use the SandboxedSdkContext to use storage
        val filename = "myfile"
        val fileContents = data.getString("extraData", "")
        try {
            mContext.openFileOutput(filename, Context.MODE_PRIVATE).use {
                it.write(fileContents.toByteArray())
                callback.onDataReceivedSuccess()
        } catch (e: Exception) {
            callback.onDataReceivedError("Unable to process data.");
        }
    }
}

Mengupdate aplikasi klien

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

  1. Dalam aktivitas aplikasi Anda yang menyertakan iklan, deklarasikan referensi ke SdkSandboxManager, boolean untuk mengetahui apakah SDK telah dimuat, dan 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;
  2. Tentukan class callback dengan menerapkan LoadSdkCallback untuk berinteraksi dengan SDK dalam runtime:

    Kotlin

    private inner class RemoteSdkCallbackImpl() : RemoteSdkCallback {
        override fun onLoadSdkSuccess(params: Bundle) {
            mSdkLoaded = true
        }
    
        override fun onLoadSdkFailure(errorCode: Int, errorMessage: String) {
            // log/show error
        }
    }
    

    Java

    private class RemoteSdkCallbackImpl implements RemoteSdkCallback {
        private RemoteSdkCallbackImpl() {}
    
        @Override
        public void onLoadSdkSuccess(Bundle params) {
            mSdkLoaded = true;
        }
    
        @Override
        public void onLoadSdkFailure(int errorCode, String errorMessage) {
            // log/show error
        }
    }
    

Untuk mendapatkan kembali tampilan jarak jauh dari SDK di runtime saat memanggil requestSurfacePackage(), tentukan class callback RequestSurfacePackageCallback:

Kotlin

private inner class RequestSurfacePackageCallbackImpl() : RequestSurfacePackageCallback {

    // Loads the remote view specified in the SDK's getView() method.
    override fun onSurfacePackageReady(
        surfacePackage: SurfacePackage,
        surfacePackageId: Int, params: Bundle
    ) {
        Handler(Looper.getMainLooper()).post {
            mClientView.setChildSurfacePackage(surfacePackage)
            mClientView.visibility = View.VISIBLE
        }
    }

    override fun onSurfacePackageError(errorCode: Int, errorMessage: String) {
        // log/show error
    }
}

Java

private class RequestSurfacePackageCallbackImpl implements RequestSurfacePackageCallback {

    // Loads the remote view specified in the SDK's getView() method.
    @Override
    public void onSurfacePackageReady(SurfacePackage surfacePackage,
            int surfacePackageId, Bundle params) {
        new Handler(Looper.getMainLooper()).post(() -> {
            mClientView.setChildSurfacePackage(surfacePackage);
            mClientView.setVisibility(View.VISIBLE);
        });
    }

    @Override
    public void onSurfacePackageError(int errorCode, String errorMessage) {
        // log/show error
    }
}

Untuk melacak status sendData() dan mendapatkan kembali data yang ditampilkan oleh SDK, tentukan class callback SendDataCallback.

Kotlin

private inner class SendDataCallbackImpl() : SendDataCallback {

    override fun onSendDataSuccess(
        params: Bundle
    ) {
        // Use the data returned by the SDK if required.
    }

    override fun onSendDataError(errorCode: Int, errorMessage: String) {
        // log/show error
    }
}

Java

private class SendDataCallbackImpl implements SendDataCallback {

    @Override
    public void onSendDataSuccess(Bundle params) {
        // Use the data returned by the SDK if required.
    }

    @Override
    public void onSendDataError(int errorCode, String errorMessage) {
        // log/show error
    }
}
  1. Di onCreate(), lakukan inisialisasi SdkSandboxManager, callback yang diperlukan, lalu buat permintaan untuk menampilkan tampilan jarak jauh:

    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
        )
    
        val sendDataCallback = SendDataCallback()
        // Send some data to the SDK if needed
        mSdkSandboxManager.sendData(SDK_NAME, Bundle(),{ obj: Runnable -> obj.run() }, sendDataCallback)
    
        val requestSurfacePackageCallback = RequestSurfacePackageCallback()
        Handler(Looper.getMainLooper()).post {
            val bundle = Bundle()
            mSdkSandboxManager.requestSurfacePackage(
                    SDK_NAME, display!!.displayId,
                    mClientView.width, mClientView.height,
                    bundle, requestSurfacePackageCallback
            )
        }
    }
    

    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);
    
        SendDataCallback sendDataCallback = new SendDataCallback();
        // Send some data to the SDK if needed
        mSdkSandboxManager.sendData(SDK_NAME, new Bundle(), Runnable::run, sendDataCallback);
    
        RequestSurfacePackageCallback requestSurfacePackageCallback = new RequestSurfacePackageCallback();
        new Handler(Looper.getMainLooper()).post(() -> {
            Bundle bundle = new Bundle();
            mSdkSandboxManager.requestSurfacePackage(
                    SDK_NAME, getDisplay().getDisplayId(),
                    mClientView.getWidth(), mClientView.getHeight(), bundle, requestSurfacePackageCallback);
        });
    }
    
  2. Tentukan ringkasan sertifikat secara manual. Untuk menemukan ringkasan sertifikat, ekstrak dari file keystore debug menggunakan keytool. Sandi default-nya adalah android.

    keytool -list -keystore ~/.android/debug.keystore
    
  3. Pada elemen <application> di file manifes aplikasi, tambahkan elemen <uses-sdk-library>. Dalam elemen ini, tetapkan atribut android:certDigest ke output dari langkah sebelumnya:

    <application ...>
      <uses-sdk-library
          android:name="com.example.basicsandboxservice"
          android:versionMajor="1"
          android:certDigest="27:76:B1:2D:...:B1:BE:E0:28:5E" />
    </application>
    

    Catatan: Jika Anda memasukkan nilai yang salah untuk android:certDigest, error berikut akan terjadi:

    Installation failed due to: 'Failed to commit install session \
    SESSION_ID with command cmd package install-commit SESSION_ID. \
    Error: INSTALL_FAILED_MISSING_SHARED_LIBRARY: Reconciliation \
    failed...: Reconcile failed: Package PACKAGE_NAME \
    requires differently signed sdk library; failing!'

Men-deploy aplikasi

Sebelum 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 SDK Anda.
  2. Buka Run > Edit Configurations. Jendela Run/Debug Configuration akan muncul.
  3. Di bagian Launch Options, tetapkan Launch ke Nothing, karena tidak ada aktivitas yang akan dimulai.
  4. Klik Apply, lalu OK.
  5. Klik Run untuk menginstal aplikasi SDK di perangkat pengujian Anda.
  6. Di jendela alat Project, buka modul aplikasi klien Anda.
  7. Buka Run > Edit Configurations. Jendela Run/Debug Configuration akan muncul.
  8. Tetapkan Launch Options ke aktivitas utama aplikasi klien Anda.
  9. Klik Apply, lalu OK.
  10. Klik Run untuk menginstal aplikasi klien 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. Men-deploy aplikasi SDK:

    ./gradlew sdk-app:installDebug
    
  2. Men-deploy aplikasi klien:

    ./gradlew client-app:installDebug && \
      # Start the app's activity. This example uses the sample app.
      adb shell am start -n \
      com.example.privacysandbox.client/com.example.client.MainActivity
    

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 (gambar 1). Centang kotak Tampilkan semua proses. Dalam daftar yang muncul, cari proses yang disebut sdk_sandbox_CLIENT_APP_UID. 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
Gambar 1. Layar Choose process, tempat Anda dapat memilih aplikasi SDK untuk di-debug

Batasan

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

Contoh kode

HalamanRepositori API Pemenuhan Privasi 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 ada masalah yang Anda temukan atau ide untuk meningkatkan Privacy Sandbox di Android.