1. Sebelum Memulai
Bayangkan Anda berada di mal yang ramai dan melihat teman Anda, Juwita. Anda mungkin akan cenderung melambaikan tangan dan berteriak sambil mencoba mendapatkan perhatian Juwita. Nearby Messages API dari Google memungkinkan aplikasi Anda melakukan teriakan yang menarik perhatian untuk pengguna, sehingga pengguna dan temannya dapat saling bertemu dengan mudah saat berada dalam jarak fisik yang dekat. Codelab ini mengajarkan cara menggunakan Nearby Messages API untuk memungkinkan interaksi pengguna berdasarkan kedekatan fisik. Agar codelab tetap sederhana, setiap pengguna akan mengungkapkan model build ponselnya: android.os.Build.MODEL
. Namun, dalam kenyataannya, Anda dapat meminta setiap pengguna mengungkapkan userId
miliknya, atau informasi lain yang sesuai dengan kasus penggunaan Anda, kepada teman-temannya di sekitar. Nearby Messages API menggabungkan konektivitas internet, Bluetooth, dan teknologi lainnya untuk menghadirkan fitur ini.
Prasyarat
- Pengetahuan dasar tentang pengembangan Kotlin dan Android
- Cara membuat dan menjalankan aplikasi di Android Studio
- Dua perangkat Android atau lebih untuk menjalankan dan menguji kode
Yang akan Anda pelajari
- Cara menambahkan library Nearby ke aplikasi
- Cara menyiarkan pesan ke pihak yang berminat
- Cara mendeteksi pesan dari lokasi minat
- Cara mendapatkan Kunci API untuk pesan
- Praktik terbaik untuk masa pakai baterai
Yang akan Anda butuhkan
- Akun Google (yaitu alamat Gmail) untuk mendapatkan Kunci Google API
- Versi terbaru Android Studio
- Dua perangkat Android yang telah menginstal Layanan Google Play (dengan kata lain, Play Store)
- Koneksi internet (Tidak seperti Nearby Connections API yang tidak memerlukannya)
Yang akan Anda bangun
Satu aplikasi Activity
yang memungkinkan pengguna memberitahukan informasi perangkat dan menerima informasi tentang perangkat di sekitar. Aplikasi memiliki dua tombol yang dapat dialihkan oleh pengguna: tombol pertama adalah untuk menemukan atau menghentikan penemuan pesan di sekitar; tombol kedua adalah untuk memublikasikan atau membatalkan publikasi pesan. Untuk aplikasi ini, kita ingin publikasi dan penemuan berhenti setelah sekitar 120 detik. Untuk itu, kita akan menggali sedikit lebih dalam tentang API, membuat objek PublishOptions
dan SubscribeOptions
, serta menggunakan callback onExpired()
untuk menonaktifkan tombol UI publikasikan dan berlangganan.
2. Membuat project Android Studio
- Mulai project Android Studio baru.
- Pilih Empty Activity.
- Beri nama project Nearby Messages Example dan setel bahasa ke Kotlin.
3. Menyiapkan kode
- Tambahkan versi terbaru dependensi Nearby ke dalam file
build.gradle
tingkat aplikasi Anda. Penambahan ini memungkinkan Anda menggunakan Nearby Messages API untuk mengirim dan mendeteksi pesan dari perangkat di sekitar.
implementation 'com.google.android.gms:play-services-nearby:18.0.0'
- Tetapkan opsi build viewBinding ke
true
dalam blok Android untuk mengaktifkan ViewBinding.
android {
...
buildFeatures {
viewBinding true
}
}
- Klik Sync Now atau tombol palu hijau untuk mengaktifkan Android Studio guna mendaftarkan perubahan Gradle ini.
- Tambahkan tombol beralih "Discover nearby devices" dan "Share device information" serta RecycleView yang akan berisi daftar perangkat. Di file
activity_main.xml
, ganti kode dengan kode berikut.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/subscribe_switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Discover nearby devices" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/publish_switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Share device information" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/nearby_msg_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:transcriptMode="alwaysScroll" />
</LinearLayout>
Catatan: Di project Anda sendiri, ubah nilai seperti 16dp
ke resource seperti @dimen/activity_vertical_margin
.
4. Menambahkan Nearby Messages ke aplikasi
Menentukan variabel
- Di dalam aktivitas utama (
MainActivity.kt
), di atas fungsionCreate()
, tentukan variabel berikut dengan menempelkan cuplikan kode ini.
/**
* For accessing layout variables
*/
private lateinit var binding: ActivityMainBinding
/**
* Sets the time to live in seconds for the publish or subscribe.
*/
private val TTL_IN_SECONDS = 120 // Two minutes.
/**
* Choose of strategies for publishing or subscribing for nearby messages.
*/
private val PUB_SUB_STRATEGY = Strategy.Builder().setTtlSeconds(TTL_IN_SECONDS).build()
/**
* The [Message] object used to broadcast information about the device to nearby devices.
*/
private lateinit var message: Message
/**
* A [MessageListener] for processing messages from nearby devices.
*/
private lateinit var messageListener: MessageListener
/**
* MessageAdapter is a custom class that we will define later. It's for adding
* [messages][Message] to the [RecyclerView]
*/
private lateinit var msgAdapter: MessageAdapter
Kita menentukan Strategy
karena ingin menyesuaikan seberapa lama siaran harus berlangsung. Untuk codelab ini, kita akan memilih 120 detik. Jika Anda tidak menentukan strategi, API akan menggunakan setelan default untuk Anda. Selain itu, meskipun kita menggunakan Strategy
yang sama untuk publikasi dan langganan dalam codelab ini, Anda tidak diharuskan melakukannya.
- Ubah fungsi
onCreate()
untuk meneruskan objek ViewBinding kesetContentView()
. Ini akan menampilkan isi file tata letakactivity_main.xml
.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
Menghubungkan tombol UI
Aplikasi ini akan melakukan tiga hal: memublikasikan pesan dengan cepat, menemukan pesan dengan cepat, dan menampilkan pesan dalam RecyclerView
.
- Kita ingin pengguna memublikasikan dan membatalkan publikasi pesan serta menemukan (yaitu berlangganan) pesan. Untuk saat ini, buat metode stub untuk tindakan ini, yang disebut
publish()
,unpublish()
,subscribe()
,unsubscribe()
. Kita akan membuat implementasi tersebut pada langkah berikutnya.
private fun publish() {
TODO("Not yet implemented")
}
private fun unpublish() {
TODO("Not yet implemented")
}
private fun subscribe() {
TODO("Not yet implemented")
}
private fun unsubscribe() {
TODO("Not yet implemented")
}
- Pengguna dapat memublikasikan atau menemukan (yaitu berlangganan) pesan menggunakan tombol yang ditambahkan ke tata letak aktivitas. Hubungkan kedua
Switches
untuk memanggil metode yang telah kita tentukan di akhir fungsionCreate()
.
binding.subscribeSwitch.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
subscribe()
} else {
unsubscribe()
}
}
binding.publishSwitch.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
publish()
} else {
unpublish()
}
}
- Setelah Anda menambahkan kode UI untuk memublikasikan dan menemukan pesan, siapkan
RecyclerView
untuk menampilkan dan menghapus pesan.RecyclerView
akan menampilkan pesan yang sedang aktif dipublikasikan. Pelanggan akan memproses pesan. Ketika pesan ditemukan, pelanggan akan menambahkannya keRecyclerView
; saat pesan hilang, dengan kata lain penerbit berhenti memublikasikannya, pelanggan akan menghapusnya dariRecyclerView
.
private fun setupMessagesDisplay() {
msgAdapter = MessageAdapter()
with(binding.nearbyMsgRecyclerView) {
layoutManager = LinearLayoutManager(context)
this.adapter = msgAdapter
}
}
class MessageAdapter : RecyclerView.Adapter<MessageAdapter.MessageVH>() {
private var itemsList: MutableList<String> = arrayListOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageVH {
return MessageVH(TextView(parent.context))
}
override fun onBindViewHolder(holder: MessageVH, position: Int) {
holder.bind(getItem(position))
}
override fun getItemCount(): Int = itemsList.size
private fun getItem(pos: Int): String? = if (itemsList.isEmpty()) null else itemsList[pos]
fun addItem(item: String) {
itemsList.add(item)
notifyItemInserted(itemsList.size)
}
fun removeItem(item: String) {
val pos = itemsList.indexOf(item)
itemsList.remove(item)
notifyItemRemoved(pos)
}
inner class MessageVH(private val tv: TextView) : RecyclerView.ViewHolder(tv) {
fun bind(item: String?) {
item?.let { tv.text = it }
}
}
}
- Di akhir fungsi
onCreate()
, tambahkan panggilan ke fungsisetupMessagesDisplay()
.
override fun onCreate(savedInstanceState: Bundle?) {
...
setupMessagesDisplay()
}
Setelah UI siap, kita siap untuk mulai memublikasikan pesan agar ditemukan oleh perangkat lain di sekitar. Berikut adalah tampilan aplikasi Anda pada tahap ini:
Menambahkan kode publikasi dan penemuan
- Untuk mengirim pesan, pertama-tama kita memerlukan objek
Message
. Karena ini adalah demo, kita hanya akan mengirimkan model perangkat. Tambahkan kode ini ke fungsionCreate()
untuk membuat pesan yang akan dikirim.
override fun onCreate(savedInstanceState: Bundle?) {
...
// The message being published is simply the Build.MODEL of the device. But since the
// Messages API is expecting a byte array, you must convert the data to a byte array.
message = Message(Build.MODEL.toByteArray(Charset.forName("UTF-8")))
}
- Untuk memublikasikan
Message
yang dapat ditemukan oleh perangkat lain di sekitar, cukup panggilNearby.getMessagesClient(activity).publish(message)
. Namun, sebaiknya buat objekPublishOptions
Anda sendiri sebelum ke langkah berikutnya. Hal ini memungkinkan Anda menentukanStrategy
kustom Anda sendiri dan memanfaatkanPublishCallback
, yang akan memberi tahu saat masa berlaku pesan yang dipublikasikan telah berakhir. Dalam kode berikut, kita akan membuat opsi agar dapat menonaktifkan tombol untuk pengguna saat masa berlakuTTL
yang dipublikasikan berakhir. Selanjutnya, kita meneruskan opsi saat memanggilpublish()
. Update fungsipublish()
dengan kode berikut.
private fun publish() {
val options = PublishOptions.Builder()
.setStrategy(PUB_SUB_STRATEGY)
.setCallback(object : PublishCallback() {
override fun onExpired() {
super.onExpired()
// flick the switch off since the publishing has expired.
// recall that we had set expiration time to 120 seconds
// Use runOnUiThread to force the callback
// to run on the UI thread
runOnUiThread{
binding.publishSwitch.isChecked = false
}
}
}).build()
Nearby.getMessagesClient(this).publish(message, options)
}
Kode ini berjalan setiap kali pengguna MENGAKTIFKAN tombol publish.
- Publikasi memerlukan
Message
, sedangkan langganan memerlukanMessageListener
. Namun, sebaiknya Anda membuat objekSubscribeOptions
meskipun tidak diperlukan untuk membuat API berfungsi. Dengan membuatSubscriptionOption
sendiri, Anda dapat menentukan, misalnya, berapa lama Anda ingin berada dalam mode penemuan.
Tambahkan kode MessageListener
berikut ke fungsi onCreate()
. Saat pesan terdeteksi, pemroses akan menambahkannya ke RecyclerView
. Saat pesan hilang, pemroses akan menghapusnya dari RecyclerView
.
messageListener = object : MessageListener() {
override fun onFound(message: Message) {
// Called when a new message is found.
val msgBody = String(message.content)
msgAdapter.addItem(msgBody)
}
override fun onLost(message: Message) {
// Called when a message is no longer detectable nearby.
val msgBody = String(message.content)
msgAdapter.removeItem(msgBody)
}
}
- Secara teknis, pelanggan tidak memerlukan
TTL
(atau dapat menyetelTTL
ke infinity). Namun, dalam codelab ini, kita ingin menghentikan penemuan setelah 120 detik. Dengan demikian, kita akan membuatSubscribeOptions
kita sendiri dan menggunakan callbackonExpired()
untuk menonaktifkanSwitch
UI berlangganan. Update fungsi berlangganan dengan kode ini.
private fun subscribe() {
val options = SubscribeOptions.Builder()
.setStrategy(PUB_SUB_STRATEGY)
.setCallback(object : SubscribeCallback() {
override fun onExpired() {
super.onExpired()
// flick the switch off since the subscribing has expired.
// recall that we had set expiration time to 120 seconds
// Use runOnUiThread to force the callback
// to run on the UI thread
runOnUiThread {
binding.subscribeSwitch.isChecked = false
}
}
}).build()
Nearby.getMessagesClient(this).subscribe(messageListener, options)
}
- Penting untuk memungkinkan pengguna menonaktifkan fungsi berbagi informasi. Artinya, penerbit dapat menghentikan publikasi dan memungkinkan pelanggan berhenti berlangganan. Untuk berhenti memublikasikan, penerbit harus menentukan pesan yang ingin dihentikan publikasinya. Oleh karena itu, jika Anda memiliki sepuluh pesan yang sedang disiarkan, Anda dapat menghentikan publikasi satu pesan, lalu membiarkan sembilan pesan tetap dipublikasikan.
private fun unpublish() {
Nearby.getMessagesClient(this).unpublish(message)
}
- Meskipun dapat memublikasikan beberapa pesan sekaligus, aplikasi hanya dapat memiliki satu
MessageListener
dalam satu waktu. Oleh karena itu, berhenti berlangganan bersifat lebih umum. Untuk berhenti berlangganan, pelanggan harus menentukan pemroses.
private fun unsubscribe() {
Nearby.getMessagesClient(this).unsubscribe(messageListener)
}
- Sebagai catatan, meskipun API harus menghentikan prosesnya ketika proses klien berhenti, Anda mungkin ingin berhenti berlangganan (dan publikasi jika mungkin) dalam metode siklus proses
onDestroy()
.
override fun onDestroy() {
super.onDestroy()
// although the API should shutdown its processes when the client process dies,
// you may want to stop subscribing (and publishing if convenient)
Nearby.getMessagesClient(this).unpublish(message)
Nearby.getMessagesClient(this).unsubscribe(messageListener)
}
Pada tahap ini, kode kita seharusnya sudah terkompilasi. Namun, aplikasi tidak akan berfungsi seperti yang diharapkan karena kunci API tidak ada. MainActivity
Anda akan terlihat seperti ini:
package com.example.nearbymessagesexample
import android.os.Build
import android.os.Bundle
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.nearbymessagesexample.databinding.ActivityMainBinding
import com.google.android.gms.nearby.Nearby
import com.google.android.gms.nearby.messages.Message
import com.google.android.gms.nearby.messages.MessageListener
import com.google.android.gms.nearby.messages.PublishCallback
import com.google.android.gms.nearby.messages.PublishOptions
import com.google.android.gms.nearby.messages.Strategy
import com.google.android.gms.nearby.messages.SubscribeCallback
import com.google.android.gms.nearby.messages.SubscribeOptions
import java.nio.charset.Charset
class MainActivity : AppCompatActivity() {
/**
* For accessing layout variables
*/
private lateinit var binding: ActivityMainBinding
/**
* Sets the time to live in seconds for the publish or subscribe.
*/
private val TTL_IN_SECONDS = 120 // Two minutes.
/**
* Choose of strategies for publishing or subscribing for nearby messages.
*/
private val PUB_SUB_STRATEGY = Strategy.Builder().setTtlSeconds(TTL_IN_SECONDS).build()
/**
* The [Message] object used to broadcast information about the device to nearby devices.
*/
private lateinit var message: Message
/**
* A [MessageListener] for processing messages from nearby devices.
*/
private lateinit var messageListener: MessageListener
/**
* For adding [messages][Message] to the [RecyclerView]
*/
private lateinit var msgAdapter: MessageAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.subscribeSwitch.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
subscribe()
} else {
unsubscribe()
}
}
binding.publishSwitch.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
publish()
} else {
unpublish()
}
}
setupMessagesDisplay()
// The message being published is simply the Build.MODEL of the device. But since the
// Messages API is expecting a byte array, you must convert the data to a byte array.
message = Message(Build.MODEL.toByteArray(Charset.forName("UTF-8")))
messageListener = object : MessageListener() {
override fun onFound(message: Message) {
// Called when a new message is found.
val msgBody = String(message.content)
msgAdapter.addItem(msgBody)
}
override fun onLost(message: Message) {
// Called when a message is no longer detectable nearby.
val msgBody = String(message.content)
msgAdapter.removeItem(msgBody)
}
}
}
override fun onDestroy() {
super.onDestroy()
// although the API should shutdown its processes when the client process dies,
// you may want to stop subscribing (and publishing if convenient)
Nearby.getMessagesClient(this).unpublish(message)
Nearby.getMessagesClient(this).unsubscribe(messageListener)
}
private fun publish() {
val options = PublishOptions.Builder()
.setStrategy(PUB_SUB_STRATEGY)
.setCallback(object : PublishCallback() {
override fun onExpired() {
super.onExpired()
// flick the switch off since the publishing has expired.
// recall that we had set expiration time to 120 seconds
runOnUiThread {
binding.publishSwitch.isChecked = false
}
runOnUiThread() {
binding.publishSwitch.isChecked = false
}
}
}).build()
Nearby.getMessagesClient(this).publish(message, options)
}
private fun unpublish() {
Nearby.getMessagesClient(this).unpublish(message)
}
private fun subscribe() {
val options = SubscribeOptions.Builder()
.setStrategy(PUB_SUB_STRATEGY)
.setCallback(object : SubscribeCallback() {
override fun onExpired() {
super.onExpired()
runOnUiThread {
binding.subscribeSwitch.isChecked = false
}
}
}).build()
Nearby.getMessagesClient(this).subscribe(messageListener, options)
}
private fun unsubscribe() {
Nearby.getMessagesClient(this).unsubscribe(messageListener)
}
private fun setupMessagesDisplay() {
msgAdapter = MessageAdapter()
with(binding.nearbyMsgRecyclerView) {
layoutManager = LinearLayoutManager(context)
this.adapter = msgAdapter
}
}
class MessageAdapter : RecyclerView.Adapter<MessageAdapter.MessageVH>() {
private var itemsList: MutableList<String> = arrayListOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageVH {
return MessageVH(TextView(parent.context))
}
override fun onBindViewHolder(holder: MessageVH, position: Int) {
holder.bind(getItem(position))
}
override fun getItemCount(): Int = itemsList.size
private fun getItem(pos: Int): String? = if (itemsList.isEmpty()) null else itemsList[pos]
fun addItem(item: String) {
itemsList.add(item)
notifyItemInserted(itemsList.size)
}
fun removeItem(item: String) {
val pos = itemsList.indexOf(item)
itemsList.remove(item)
notifyItemRemoved(pos)
}
inner class MessageVH(private val tv: TextView) : RecyclerView.ViewHolder(tv) {
fun bind(item: String?) {
item?.let { tv.text = it }
}
}
}
}
Menambahkan Kunci API dari Google ke file manifes
Nearby Messages API memiliki komponen server yang disediakan Google untuk Anda. Saat Anda memublikasikan pesan, Nearby Messages API akan mengirimkan pesan ke server Google, tempat pelanggan kemudian dapat mengkueri pesan tersebut. Agar Google dapat mengenali aplikasi, Anda perlu menambahkan API_KEY
dari Google ke file Manifest.xml
. Setelah itu, kita dapat langsung menjalankan dan mencoba menggunakan aplikasi.
Mendapatkan Kunci API merupakan proses tiga langkah:
- Buka Google Developers Console.
- Klik + Create Credentials, lalu pilih API Key*.*
- Salin kunci API yang dibuat dan tempel ke file manifes project Android Anda.
Tambahkan item metadata com.google.android.nearby.messages.API_KEY
di dalam aplikasi di file manifes Anda. File tersebut akan terlihat seperti ini.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.nearbymessagesexample">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.NearbyMessagesExample">
<meta-data
android:name="com.google.android.nearby.messages.API_KEY"
android:value="ADD_KEY_HERE" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Setelah Anda menambahkan Kunci API, jalankan aplikasi pada dua perangkat atau lebih untuk melihatnya saling berkomunikasi.
5. Praktik terbaik untuk masa pakai baterai
- Untuk melindungi privasi pengguna dan menghemat masa pakai baterai, Anda harus berhenti memublikasikan dan berlangganan segera setelah pengguna meninggalkan fitur tempat fungsi tersebut diperlukan.
- Anda harus menggunakan Nearby Messages untuk membangun kedekatan di antara perangkat, tetapi tidak untuk komunikasi berkelanjutan. Komunikasi berkelanjutan dapat menguras baterai perangkat dengan kecepatan 2,5 hingga 3,5 kali lipat dari rasio konsumsi baterai normal.
6. Selamat
Selamat! Anda sekarang telah mengetahui cara mengirim dan menemukan pesan antara perangkat di sekitar menggunakan Nearby Messages API.
Singkatnya, untuk menggunakan Nearby Messages API, Anda perlu menambahkan dependensi untuk play-services-nearby
dan mendapatkan Kunci API dari Google Developers Console, lalu menambahkannya ke file Manifest.xml
Anda. API memerlukan koneksi internet agar penerbit dapat mengirimkan pesannya ke server Google sehingga dapat diambil oleh pelanggan.
- Anda telah mempelajari cara mengirim pesan
- Anda telah mempelajari cara berlangganan untuk menemukan pesan
- Anda telah mempelajari cara menggunakan pesan (dalam hal ini Anda cukup menampilkannya di
RecyclerView
)
Apa Selanjutnya?
Lihat rangkaian blog dan contoh kami