Sinkronisasi dan akses jaringan di Wear

Dengan Wear OS by Google, smartwatch dapat langsung berkomunikasi dengan jaringan, tanpa akses ke ponsel Android atau iOS. Akses jaringan langsung ini menggantikan penggunaan Data Layer API (di Wear 1.x) untuk terhubung ke jaringan.

Akses jaringan

Aplikasi Wear OS dapat membuat permintaan jaringan. Bila smartwatch terhubung ke ponsel melalui Bluetooth, traffic jaringannya secara umum dilewatkan proxy melalui ponsel. Namun, bila ponsel tidak tersedia, jaringan Wi-Fi dan seluler akan digunakan, tergantung pada hardware. Platform Wear dapat menangani transisi antar-jaringan.

Anda dapat menggunakan protokol seperti HTTP, TCP, dan UDP. Namun, API android.webkit (termasuk class CookieManager) tidak tersedia. Anda dapat menggunakan cookie dengan membaca dan menulis header pada permintaan dan respons.

Selain itu, sebaiknya gunakan:

  • JobScheduler API untuk tugas asinkron, termasuk polling dengan interval rutin (dijelaskan di bawah ini)
  • API multi-jaringan jika perlu terhubung ke jenis jaringan tertentu; lihat Koneksi Multi-jaringan

Akses jaringan bandwidth tinggi

Platform Wear OS mengelola konektivitas jaringan untuk menyediakan pengalaman pengguna terbaik secara keseluruhan. Platform ini memilih jaringan default yang aktif dengan menyeimbangkan dua faktor:

  • Kebutuhan akan masa pakai baterai yang tahan lama
  • Kebutuhan akan bandwidth jaringan

Bila ketahanan baterai diprioritaskan, jaringan aktif mungkin tidak memiliki cukup bandwidth untuk melakukan tugas jaringan yang memerlukan bandwidth tinggi, seperti memindahkan file besar atau streaming media.

Bagian ini menyediakan panduan tentang penggunaan class ConnectivityManager guna memastikan bahwa bandwidth jaringan yang diperlukan tersedia untuk aplikasi. Untuk informasi umum tentang kontrol terperinci atas resource jaringan, lihat Mengelola Penggunaan Jaringan.

Memperoleh jaringan dengan bandwidth tinggi

Pada Wear OS, jangan berasumsi bahwa jaringan dengan bandwidth tinggi selalu tersedia. Untuk kasus penggunaan yang memerlukan akses jaringan bandwidth tinggi, seperti memindahkan file besar atau streaming media, sebaiknya ikuti langkah-langkah berikut:

  1. Periksa apakah ada jaringan yang aktif, dan jika ada, periksa bandwidth jaringan tersebut.
  2. Jika tidak ada jaringan yang aktif, atau bandwidth jaringan tidak mencukupi, minta akses ke jaringan seluler atau Wi-Fi tidak berbayar.

Anda dapat menggunakan class ConnectivityManager untuk memeriksa apakah ada jaringan yang aktif dan memiliki cukup bandwidth:

Kotlin

const val MIN_BANDWIDTH_KBPS = 320
connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val bandwidth: Int = connectivityManager.activeNetwork?.let { activeNetwork ->
    connectivityManager.getNetworkCapabilities(activeNetwork).linkDownstreamBandwidthKbps
} ?: -1

when {
    bandwidth < 0 -> {
        // No active network
    }
    bandwidth in (0 until MIN_BANDWIDTH_KBPS) -> {
        // Request a high-bandwidth network
    }
    else -> {
        // You already are on a high-bandwidth network, so start your network request
    }
}

Java

int MIN_BANDWIDTH_KBPS = 320;
connectivityManager =
  (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
Network activeNetwork = connectivityManager.getActiveNetwork();

if (activeNetwork != null) {
  int bandwidth =
    connectivityManager.getNetworkCapabilities(activeNetwork).getLinkDownstreamBandwidthKbps();

  if (bandwidth < MIN_BANDWIDTH_KBPS) {
    // Request a high-bandwidth network
  } else {
    // You already are on a high-bandwidth network, so start your network request
  }
} else {
  // No active network
}

Anda dapat meminta jaringan bandwidth tinggi yang tidak berbayar menggunakan ConnectivityManager. Dengan satu permintaan jaringan, Anda dapat meminta jaringan seluler atau Wi-Fi tidak berbayar. Saat jaringan siap (misalnya, radio Wi-Fi perangkat terhubung ke jaringan tersimpan), metode onAvailable() instance NetworkCallback akan dipanggil. Jika jaringan yang cocok tidak ditemukan, metode onAvailable() tidak akan dipanggil. Oleh karena itu, Anda harus membatalkan permintaan secara manual karena waktu habis; lihat Menunggu Ketersediaan Jaringan.

Kotlin

networkCallback = object : ConnectivityManager.NetworkCallback() {
    override fun onAvailable(network: Network) {
        if (bindProcessToNetwork(network)) {
            // socket connections will now use this network
        } else {
            // app doesn't have android.permission.INTERNET permission
        }
    }
}

val request: NetworkRequest = NetworkRequest.Builder().run {
    addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
    addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
    addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
    addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    build()
}

connectivityManager.requestNetwork(request, networkCallback)

Java

networkCallback = new ConnectivityManager.NetworkCallback() {
  @Override
  public void onAvailable(Network network) {
    if (bindProcessToNetwork(network)) {
      // socket connections will now use this network
    } else {
      // app doesn't have android.permission.INTERNET permission
    }
  }
};

NetworkRequest request = new NetworkRequest.Builder()
  .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
  .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
  .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
  .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
  .build();

connectivityManager.requestNetwork(request, networkCallback);

Melepaskan jaringan

Bila aplikasi sudah tidak lagi memerlukan jaringan dengan bandwidth tinggi, Anda harus melepaskan jaringan menggunakan class ConnectivityManager untuk memastikan bahwa platform dapat melanjutkan pengelolaan akses jaringan.

Kotlin

connectivityManager.bindProcessToNetwork(null)
connectivityManager.unregisterNetworkCallback(networkCallback)

Java

connectivityManager.bindProcessToNetwork(null);
connectivityManager.unregisterNetworkCallback(networkCallback);

Untuk mengoptimalkan penggunaan baterai, koneksi jaringan harus tetap terdaftar selama aktivitas berlangsung. Oleh karena itu, Anda harus mempertimbangkan untuk melepaskan jaringan dalam metode onStop() aktivitas.

Menunggu ketersediaan jaringan

Jaringan mungkin tidak dapat langsung diperoleh karena radio Wi-Fi atau seluler smartwatch dapat mati untuk menghemat baterai. Selain itu, jika smartwatch tidak dapat terhubung ke jaringan, metode onAvailable() instance NetworkCallback tidak akan dipanggil. Oleh karena itu, Anda harus membatalkan permintaan setelah jangka waktu yang ditentukan dan melepaskan setiap resource terkait.

Kotlin

const val MESSAGE_CONNECTIVITY_TIMEOUT = 1
const val NETWORK_CONNECTIVITY_TIMEOUT_MS: Long = 10000
...
handler = MyHandler()

networkCallback = object : ConnectivityManager.NetworkCallback() {
    override fun onAvailable(network: Network) {
        handler.removeMessages(MESSAGE_CONNECTIVITY_TIMEOUT)
        ...
    }
}

connectivityManager.requestNetwork(request, networkCallback)

handler.sendMessageDelayed(
        handler.obtainMessage(MESSAGE_CONNECTIVITY_TIMEOUT),
        NETWORK_CONNECTIVITY_TIMEOUT_MS
)
...
// Don't make this an inner class otherwise there is the potential to leak the parent class
private class MyHandler : Handler() {
    override fun handleMessage(msg: Message) {
        when (msg.what) {
            MESSAGE_CONNECTIVITY_TIMEOUT -> {
                // unregister the network
            }
        }
    }
}

Java

int MESSAGE_CONNECTIVITY_TIMEOUT = 1;
long NETWORK_CONNECTIVITY_TIMEOUT_MS = 10000;

handler = new MyHandler();

networkCallback = new ConnectivityManager.NetworkCallback() {
  @Override
  public void onAvailable(Network network) {
    handler.removeMessages(MESSAGE_CONNECTIVITY_TIMEOUT);
    ...
  }
};

connectivityManager.requestNetwork(request, networkCallback);

handler.sendMessageDelayed(
  handler.obtainMessage(MESSAGE_CONNECTIVITY_TIMEOUT),
  NETWORK_CONNECTIVITY_TIMEOUT_MS);

...
// This needs to be static to avoid potentially leaking the parent class
private static class MyHandler extends Handler {
   @Override
   public void handleMessage(Message msg) {
       switch (msg.what) {
           case MESSAGE_CONNECTIVITY_TIMEOUT:
               // unregister the network
               break;
       }
   }
}

Memantau status jaringan

Antarmuka NetworkCallback memiliki metode untuk memantau perubahan status pada jaringan terikat, seperti perubahan bandwidth dan hilangnya konektivitas.

Kotlin

networkCallback = object : ConnectivityManager.NetworkCallback() {
    override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
        val bandwidth: Int = networkCapabilities.linkDownstreamBandwidthKbps

        if (bandwidth < MIN_BANDWIDTH_KBPS) {
            // handle insufficient network bandwidth
        }
    }

    override fun onLost(network: Network) {
        // handle network loss
    }
}

Java

networkCallback = ConnectivityManager.NetworkCallback {
  @Override
  public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
    int bandwidth = networkCapabilities.getLinkDownstreamBandwidthKbps();

      if (bandwidth < MIN_BANDWIDTH_KBPS) {
        // handle insufficient network bandwidth
      }
  }

  @Override
  public void onLost(Network network) {
    // handle network loss
  }
}

Meluncurkan aktivitas setelan Wi-Fi

Saat meminta jaringan Wi-Fi, sistem akan mencoba terhubung ke jaringan tersimpan jika telah dikonfigurasi dan berada dalam jangkauan. Namun, jika tidak ada jaringan Wi-Fi tersimpan yang tersedia, metode callback onAvailable() instance NetworkCallback tidak akan dipanggil. Jika menggunakan Handler untuk membatalkan permintaan jaringan karena waktu habis, Anda dapat mengarahkan pengguna untuk menambahkan jaringan Wi-Fi saat waktu tunggu habis. Anda dapat mengalihkan pengguna langsung ke aktivitas untuk menambahkan jaringan Wi-Fi menggunakan intent berikut:

Kotlin

context.startActivity(Intent("com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS"))

Java

context.startActivity(new Intent("com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS"));

Untuk meluncurkan aktivitas setelan, aplikasi harus memiliki izin berikut: android.permission.CHANGE_WIFI_STATE

Pertimbangan antarmuka pengguna

Jika aplikasi memerlukan koneksi ke jaringan Wi-Fi baru untuk operasi bandwidth tinggi, pastikan alasan penyambungannya jelas bagi pengguna sebelum meluncurkan setelan Wi-Fi. Hanya minta pengguna untuk menambahkan jaringan Wi-Fi baru bila jaringan bandwidth tinggi diperlukan. Jangan halangi pengguna mengakses fitur aplikasi yang tidak memerlukan jaringan bandwidth tinggi.

Sebagai contoh, Gambar 1 menunjukkan aplikasi musik. Aplikasi tersebut harus memungkinkan pengguna menjelajahi musik dan hanya mengharuskannya menambahkan jaringan Wi-Fi baru jika ingin mendownload atau menjalankan streaming musik.

Mendownload musik

Gambar 1. Alur aplikasi musik untuk mendownload musik.

Jika aplikasi memerlukan jaringan bandwidth tinggi agar dapat beroperasi, Anda harus memberikan alasan yang jelas kepada pengguna sebelum meminta pengguna menambahkan jaringan Wi-Fi baru. Selain itu, untuk operasi jaringan berdurasi lama, seperti mendownload playlist media pengguna, Anda harus menyediakan indikator progres dengan deskripsi operasi yang sedang dilakukan.

Gambar 2 menunjukkan aplikasi musik dalam alur streaming musik. Jika pengguna ingin melakukan streaming musik dan memerlukan jaringan bandwidth tinggi, aplikasi harus menjelaskan alasan jaringan Wi-Fi baru diperlukan, sebelum mengalihkan pengguna ke setelan Wi-Fi.

Streaming musik

Gambar 2. Alur aplikasi musik untuk streaming musik.

Cloud messaging

Untuk mengirim notifikasi, aplikasi dapat langsung menggunakan FCM (Firebase Cloud Messaging), yang menggantikan GCM (Google Cloud Messaging). FCM didukung di Wear 2.0. GCM tidak didukung di Wear 2.0.

Tidak ada API untuk akses jaringan atau FCM yang spesifik untuk Wear OS. Lihat dokumentasi yang ada tentang menyambung ke jaringan dan cloud messaging.

FCM berfungsi dengan mode Istirahatkan dan merupakan cara yang direkomendasikan untuk mengirimkan notifikasi ke smartwatch.

Sediakan pesan dari FCM dengan mengumpulkan token pendaftaran untuk perangkat saat aplikasi Wear dijalankan. Kemudian, sertakan token sebagai bagian dari tujuan saat server mengirim pesan ke endpoint REST FCM. FCM akan mengirim pesan ke perangkat yang teridentifikasi oleh token.

Pesan FCM memiliki format JSON dan dapat menyertakan salah satu atau kedua payload berikut:

  • Payload notifikasi. Saat payload notifikasi diterima oleh smartwatch, data akan ditampilkan langsung kepada pengguna dalam aliran notifikasi. Aplikasi akan diluncurkan saat pengguna mengetuk notifikasi.
  • Payload data. Payload ini memiliki sekumpulan key-value pair kustom. Payload dikirimkan sebagai data ke aplikasi Wear.

Untuk informasi selengkapnya dan contoh payload, lihat Tentang Pesan FCM.

Secara default, notifikasi akan dihubungkan (dibagikan) dari aplikasi ponsel ke smartwatch. Jika Anda memiliki aplikasi Wear mandiri dan aplikasi ponsel terkait, notifikasi duplikat mungkin terjadi. Contohnya, notifikasi sama dari FCM, yang diterima ponsel dan smartwatch, mungkin ditampilkan masing-masing oleh kedua perangkat.

Menggunakan layanan latar belakang

Untuk memastikan bahwa tugas latar belakang dijalankan dengan benar, tugas harus mempertimbangkan mode Istirahatkan. Di Android 6.0, mode Istirahatkan dan Aplikasi Standby memperpanjang masa pakai baterai.

Mode Istirahatkan disempurnakan di Android Nougat dan Wear OS. Bila layar mati atau memasuki mode standby untuk waktu yang cukup lama, mode Istirahatkan sebagian mungkin diaktifkan dan tugas latar belakang mungkin tertunda selama jangka waktu tertentu. Kemudian, bila standby lebih lama, perangkat akan memasuki mode Istirahatkan biasa.

Anda harus menjadwalkan tugas dengan JobScheduler API, yang memungkinkan aplikasi mendaftarkan eksekusi kode yang aman terhadap mode Istirahatkan. Saat menjadwalkan tugas, Anda dapat memilih batasan seperti eksekusi berkala dan perlunya konektivitas atau pengisian daya perangkat. Konfigurasikan tugas dengan cara yang tidak berdampak buruk pada masa pakai baterai. Tugas harus menggunakan objek JobInfo.Builder untuk menyediakan batasan dan metadata, misalnya dengan satu atau beberapa metode berikut untuk satu tugas:

  • Untuk menjadwalkan tugas yang memerlukan jaringan, gunakan setRequiredNetworkType(int networkType), dengan menentukan NETWORK_TYPE_ANY atau NETWORK_TYPE_UNMETERED; perlu diketahui bahwa NETWORK_TYPE_UNMETERED ditujukan untuk transfer data berukuran besar, sementara NETWORK_TYPE_ANY untuk transfer berukuran kecil
  • Untuk menjadwalkan tugas saat mengisi daya, gunakan setRequiresCharging(boolean requiresCharging)
  • Untuk menetapkan agar perangkat tidak menjalankan suatu tugas, gunakan setRequiresDeviceIdle(boolean requiresDeviceIdle); metode ini berguna untuk pekerjaan latar belakang dengan prioritas lebih rendah atau sinkronisasi, khususnya bila digunakan dengan setRequiresCharging

Perlu diketahui bahwa jaringan bandwidth rendah tertentu, seperti Bluetooth LE, dianggap berbayar.

Menjadwalkan dengan batasan

Anda dapat menjadwalkan tugas yang mengharuskan batasan. Dalam contoh di bawah ini, objek JobScheduler mengaktifkan MyJobService bila batasan berikut terpenuhi:

  • Jaringan tidak berbayar
  • Pengisian daya perangkat

Anda dapat menggunakan metode builder setExtras untuk melampirkan paket metadata khusus aplikasi ke permintaan tugas. Saat tugas dijalankan, paket ini akan disediakan ke layanan tugas. Perlu diketahui bahwa nilai MY_JOB_ID diteruskan ke konstruktor JobInfo.Builder. Nilai MY_JOB_ID ini adalah ID yang disediakan oleh aplikasi. Panggilan selanjutnya untuk membatalkan, dan tugas selanjutnya yang dibuat dengan nilai yang sama akan memperbarui tugas yang ada:

Kotlin

JobInfo.Builder(MY_JOB_ID,
        ComponentName(this, MyJobService::class.java))
        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
        .setRequiresCharging(true)
        .setExtras(extras)
        .build()
        .also { jobInfo ->
            (getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler)
                    .schedule(jobInfo)
        }

Java

JobInfo jobInfo = new JobInfo.Builder(MY_JOB_ID,
        new ComponentName(this, MyJobService.class))
        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
        .setRequiresCharging(true)
        .setExtras(extras)
        .build();
((JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE))
        .schedule(jobInfo);

Berikut adalah implementasi JobService untuk menangani tugas di atas. Saat tugas dijalankan, objek JobParameters diteruskan ke metode onStartJob. Objek JobParameters memungkinkan Anda mendapatkan nilai ID pekerjaan beserta paket tambahan yang disediakan saat menjadwalkan tugas. Metode onStartJob dipanggil pada thread aplikasi utama, dan oleh karena itu, setiap logika bernilai tinggi harus dijalankan dari thread terpisah. Dalam contoh, AsyncTask digunakan untuk menjalankan kode di latar belakang. Saat pekerjaan selesai, Anda harus memanggil metode jobFinished untuk memberi tahu JobScheduler bahwa tugas sudah selesai:

Kotlin

private class MyJobService : JobService() {

    override fun onStartJob(params: JobParameters): Boolean {
        JobAsyncTask().execute(params)
        return true
    }

    private class JobAsyncTask : AsyncTask<...>() { ... }
}

Java

public class MyJobService extends JobService {
    @Override public boolean onStartJob(JobParameters params) {
        new JobAsyncTask().execute(params);
        return true;
    }

    private class JobAsyncTask extends AsyncTask