Android uygulamaları, yayınla-abone ol tasarım kalıbına benzer şekilde Android sisteminden ve diğer Android uygulamalarından yayın mesajları gönderip alabilir. Bu yayınlar, ilgilenilen bir etkinlik gerçekleştiğinde gönderilir. Örneğin, Android sistemi, sistem başlatıldığında veya cihaz şarj olmaya başladığında çeşitli sistem etkinlikleri gerçekleştiğinde yayın gönderir. Uygulamalar ayrıca, örneğin, diğer uygulamalara ilgilenebilecekleri bir şey (örneğin, bazı yeni veriler indirilmiş) hakkında bildirimde bulunmak için özel yayınlar da gönderebilir.
Sistem, en iyi sistem sağlığını korumak için yayınların yayınını optimize eder. Bu nedenle, yayınların teslim süreleri garanti edilmez. Düşük gecikmeli işlemler arası iletişime ihtiyaç duyan uygulamalar bağlı hizmetleri kullanmayı düşünmelidir.
Uygulamalar belirli yayınları almak için kaydolabilir. Bir yayın gönderildiğinde sistem, yayınları otomatik olarak ilgili yayın türünü almak için abone olan uygulamalara yönlendirir.
Genel olarak yayınlar, uygulamalar arasında ve normal kullanıcı akışının dışında bir mesajlaşma sistemi olarak kullanılabilir. Ancak, yayınlara yanıt verme ve sistem performansını yavaşlatabilecek işleri arka planda çalıştırma fırsatını kötüye kullanmamaya dikkat etmelisiniz.
Sistem yayınları hakkında
Sistem, çeşitli sistem olayları gerçekleştiğinde (ör. sistemin uçak moduna geçmesi veya modundan çıkması) otomatik olarak yayınlar gönderir. Sistem yayınları, etkinliği almak için abone olan tüm uygulamalara gönderilir.
Yayın mesajının kendisi, işlem dizesinin gerçekleşen etkinliği tanımlayan bir Intent
nesnesi içine sarmalanır (örneğin, android.intent.action.AIRPLANE_MODE
). Amaç, ekstra alanına paketlenmiş ek bilgiler de içerebilir. Örneğin, uçak modu amacı, Uçak Modu'nun açık olup olmadığını belirten bir boole ekstra değeri içerir.
Niyetlerin nasıl okunacağı ve bir amaçtan işlem dizesinin nasıl alınacağı hakkında daha fazla bilgi için Niyetler ve Amaç Filtreleri bölümüne bakın.
Sistem yayın işlemlerinin tam listesi için Android SDK'daki BROADCAST_ACTIONS.TXT
dosyasına bakın. Her yayın eyleminin kendisiyle ilişkilendirilmiş
sabit bir alanı vardır. Örneğin, ACTION_AIRPLANE_MODE_CHANGED
sabit değeri android.intent.action.AIRPLANE_MODE
olur. Her yayın eyleminin belgeleri,
ilgili sabit alanda mevcuttur.
Sistem yayınlarındaki değişiklikler
Android platformu geliştikçe, sistem yayınlarının davranış biçimi de düzenli olarak değişir. Android'in tüm sürümlerini desteklemek için aşağıdaki değişiklikleri göz önünde bulundurun.
Android 14
Uygulamalar önbelleğe alınmış durumda olduğunda, yayın yayını sistem durumu için optimize edilir. Örneğin, ACTION_SCREEN_ON
gibi daha az önemli sistem yayınları, uygulama önbelleğe alınmış durumdayken ertelenir. Uygulama, önbelleğe alınmış durumdan etkin bir işlem yaşam döngüsüne dönüştüğünde sistem, ertelenmiş tüm yayınları yayınlar.
Manifestte belirtilen önemli yayınlar, yayınlama için uygulamaları önbelleğe alınmış durumdan geçici olarak kaldırır.
Android 9
Android 9'dan itibaren (API düzeyi 28) NETWORK_STATE_CHANGED_ACTION
yayını, kullanıcının konumu veya kimliği tanımlayabilecek veriler hakkında bilgi almaz.
Ayrıca, uygulamanız Android 9 veya sonraki sürümleri çalıştıran bir cihaza yüklenmişse kablosuz ağdan sistem yayınları SSID'ler, BSSID'ler, bağlantı bilgileri veya tarama sonuçları içermez. Bu bilgileri almak için getConnectionInfo()
numaralı telefonu arayın.
Android 8.0
Android 8.0'dan (API düzeyi 26) itibaren sistem, manifest belirtilen alıcılar için ek kısıtlamalar uygular.
Uygulamanız Android 8.0 veya sonraki bir sürümü hedefliyorsa çoğu dolaylı yayın (uygulamanızı özel olarak hedeflemeyen yayınlar) için alıcı tanımlamak üzere manifest dosyasını kullanamazsınız. Kullanıcı, uygulamanızı aktif olarak kullanırken bağlama kayıtlı alıcıyı kullanmaya devam edebilirsiniz.
Android 7.0
Android 7.0 (API düzeyi 24) ve sonraki sürümler aşağıdaki sistem yayınlarını göndermez:
Ayrıca, Android 7.0 ve sonraki sürümleri hedefleyen uygulamalar CONNECTIVITY_ACTION
yayınını registerReceiver(BroadcastReceiver, IntentFilter)
kullanarak kaydetmelidir.
Manifest'te alıcı tanımlamak işe yaramaz.
Yayın alınıyor
Uygulamalar, yayınları iki şekilde alabilir: manifesto tarafından beyan edilen alıcılar ve bağlama kayıtlı alıcılar aracılığıyla.
Manifest olarak beyan edilen alıcılar
Manifest'inizde bir yayın alıcısı tanımlarsanız yayın gönderildiğinde sistem, uygulamanızı başlatır (uygulama zaten çalışmıyorsa).
Manifest dosyasında bir yayın alıcısını beyan etmek için aşağıdaki adımları uygulayın:
Uygulamanızın manifest dosyasında
<receiver>
öğesini belirtin.<!-- If this receiver listens for broadcasts sent from the system or from other apps, even other apps that you own, set android:exported to "true". --> <receiver android:name=".MyBroadcastReceiver" android:exported="false"> <intent-filter> <action android:name="APP_SPECIFIC_BROADCAST" /> </intent-filter> </receiver>
Amaç filtreleri, alıcınızın abone olduğu yayın işlemlerini belirtir.
BroadcastReceiver
alt sınıfını oluşturun veonReceive(Context, Intent)
yöntemini uygulayın. Aşağıdaki örnekteki yayın alıcısı, yayının içeriğini günlüğe kaydeder ve gösterir:Kotlin
private const val TAG = "MyBroadcastReceiver" class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { StringBuilder().apply { append("Action: ${intent.action}\n") append("URI: ${intent.toUri(Intent.URI_INTENT_SCHEME)}\n") toString().also { log -> Log.d(TAG, log) val binding = ActivityNameBinding.inflate(layoutInflater) val view = binding.root setContentView(view) Snackbar.make(view, log, Snackbar.LENGTH_LONG).show() } } } }
Java
public class MyBroadcastReceiver extends BroadcastReceiver { private static final String TAG = "MyBroadcastReceiver"; @Override public void onReceive(Context context, Intent intent) { StringBuilder sb = new StringBuilder(); sb.append("Action: " + intent.getAction() + "\n"); sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n"); String log = sb.toString(); Log.d(TAG, log); ActivityNameBinding binding = ActivityNameBinding.inflate(layoutInflater); val view = binding.root; setContentView(view); Snackbar.make(view, log, Snackbar.LENGTH_LONG).show(); } }
Görünüm bağlamayı etkinleştirmek için modül düzeyindeki build.gradle dosyanızda viewBinding'i yapılandırın.
Sistem paket yöneticisi, uygulama yüklendiğinde alıcıyı kaydeder. Alıcı daha sonra, uygulamanıza ayrı bir giriş noktası haline gelir. Böylece sistem, uygulamayı başlatıp uygulama çalışmıyorken yayını sunabilir.
Sistem, aldığı her yayını işlemek için yeni bir BroadcastReceiver
bileşen nesnesi oluşturur. Bu nesne yalnızca onReceive(Context, Intent)
çağrısının süresi boyunca geçerlidir. Kodunuz bu yöntemden geri döndüğünde, sistem bileşenin artık etkin olmadığını kabul eder.
Bağlama kayıtlı alıcılar
Bağlama kayıtlı alıcılar, kayıt bağlamları geçerli olduğu sürece yayınları alır. Örneğin, Activity
bağlamında kaydolursanız etkinlik silinmediği sürece yayın alırsınız. Uygulama bağlamına göre kaydolursanız uygulama çalıştığı sürece yayın alırsınız.
Bir alıcıyı bağlamla kaydetmek için aşağıdaki adımları uygulayın:
Uygulamanızın modül düzeyindeki derleme dosyasına AndroidX Core kitaplığının 1.9.0 veya daha yeni bir sürümünü ekleyin:
Modern
dependencies { def core_version = "1.12.0" // Java language implementation implementation "androidx.core:core:$core_version" // Kotlin implementation "androidx.core:core-ktx:$core_version" // To use RoleManagerCompat implementation "androidx.core:core-role:1.0.0" // To use the Animator APIs implementation "androidx.core:core-animation:1.0.0-rc01" // To test the Animator APIs androidTestImplementation "androidx.core:core-animation-testing:1.0.0-rc01" // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation "androidx.core:core-performance:1.0.0-beta02" // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation "androidx.core:core-google-shortcuts:1.1.0" // Optional - to support backwards compatibility of RemoteViews implementation "androidx.core:core-remoteviews:1.0.0" // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation "androidx.core:core-splashscreen:1.1.0-alpha02" }
Kotlin
dependencies { val core_version = "1.12.0" // Java language implementation implementation("androidx.core:core:$core_version") // Kotlin implementation("androidx.core:core-ktx:$core_version") // To use RoleManagerCompat implementation("androidx.core:core-role:1.0.0") // To use the Animator APIs implementation("androidx.core:core-animation:1.0.0-rc01") // To test the Animator APIs androidTestImplementation("androidx.core:core-animation-testing:1.0.0-rc01") // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation("androidx.core:core-performance:1.0.0-beta02") // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation("androidx.core:core-google-shortcuts:1.1.0") // Optional - to support backwards compatibility of RemoteViews implementation("androidx.core:core-remoteviews:1.0.0") // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation("androidx.core:core-splashscreen:1.1.0-alpha02") }
BroadcastReceiver
örneği oluşturun:Kotlin
val br: BroadcastReceiver = MyBroadcastReceiver()
Java
BroadcastReceiver br = new MyBroadcastReceiver();
IntentFilter
örneği oluşturun:Kotlin
val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
Java
IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
Yayın alıcısının dışa aktarılıp aktarılmayacağını ve cihazdaki diğer uygulamalar tarafından görülüp görülmeyeceğini seçin. Bu alıcı, sistemden veya diğer uygulamalardan, hatta sahip olduğunuz diğer uygulamalardan gönderilen yayınları dinliyorsa
RECEIVER_EXPORTED
işaretini kullanın. Bunun yerine bu alıcı yalnızca uygulamanız tarafından gönderilen yayınları dinliyorsaRECEIVER_NOT_EXPORTED
işaretini kullanın.Kotlin
val listenToBroadcastsFromOtherApps = false val receiverFlags = if (listenToBroadcastsFromOtherApps) { ContextCompat.RECEIVER_EXPORTED } else { ContextCompat.RECEIVER_NOT_EXPORTED }
Java
boolean listenToBroadcastsFromOtherApps = false; if (listenToBroadcastsFromOtherApps) { receiverFlags = ContextCompat.RECEIVER_EXPORTED; } else { receiverFlags = ContextCompat.RECEIVER_NOT_EXPORTED; }
registerReceiver()
numaralı telefonu arayarak alıcıyı kaydedin:Kotlin
ContextCompat.registerReceiver(context, br, filter, receiverFlags)
Java
ContextCompat.registerReceiver(context, br, filter, receiverFlags);
Anonsları almayı durdurmak için
unregisterReceiver(android.content.BroadcastReceiver)
numaralı telefonu arayın. Artık ihtiyaç duymadığınızda veya bağlam artık geçerli olmadığında alıcının kaydını iptal ettiğinizden emin olun.Alıcıyı nereye kaydettirdiğinize ve kaydını iptal ettiğinize dikkat edin. Örneğin,
onCreate(Bundle)
ürününde bir alıcıyı etkinlik bağlamını kullanarak kaydederseniz alıcının etkinlik bağlamından sızdırılmasını önlemek içinonDestroy()
uygulamasında kaydınızı iptal etmeniz gerekir.onResume()
bölgesinde bir alıcıyı kaydederseniz birden fazla kez kaydedilmesini önlemek içinonPause()
uygulamasındaki kaydını iptal etmeniz gerekir (Duraklatıldığında yayın almak istemezseniz bu işlem gereksiz sistem yükünü azaltabilir).onSaveInstanceState(Bundle)
kaydını iptal etmeyin. Kullanıcı geçmiş yığınında geri giderse bu çağrı yapılmaz.
İşlem durumu üzerindeki etkiler
BroadcastReceiver
cihazınızın çalışıp çalışmaması, içerdiği işlemi etkileyip etkilememesi de sistem sonlandırma olasılığını değiştirebilir. Ön plan işlemi, alıcının onReceive()
yöntemini yürütür. Sistem, aşırı bellek baskısı dışında bu işlemi çalıştırır.
BroadcastReceiver onReceive()
tarihinden sonra devre dışı bırakılacaktır. Alıcının ana makine işlemi yalnızca uygulama bileşenleri kadar önemlidir. Bu işlem yalnızca manifest dosyası olarak beyan edilen bir alıcı barındırıyorsa (kullanıcının yakın zamanda veya hiç etkileşimde bulunmadığı uygulamalarda sık karşılaşılan bir durum) sistem, diğer kritik işlemlerin kaynaklarını kullanılabilir hale getirmek için onReceive()
tarihinden sonra bu alıcıyı sonlandırabilir.
Dolayısıyla yayın alıcıları, uzun süren arka plan iş parçacıklarını başlatmamalıdır.
Sistem, belleği geri kazanmak için onReceive()
tarihinden sonra herhangi bir anda işlemi durdurabilir ve oluşturulan iş parçacığını sonlandırabilir. Sürecin devam etmesini sağlamak için JobScheduler
kullanarak alıcıdan bir JobService
plan yapın. Böylece sistem, sürecin hâlâ çalıştığını anlar.
Arka Plan Çalışmasına Genel Bakış bölümünde daha ayrıntılı bilgi bulabilirsiniz.
Yayın gönderme
Android, uygulamaların yayın göndermesi için üç yol sağlar:
sendOrderedBroadcast(Intent, String)
yöntemi, yayınları tek seferde bir alıcıya gönderir. Her alıcı sırayla yürüttükçe, bir sonucu sonraki alıcıya iletebilir veya yayını tamamen iptal ederek diğer alıcılara iletilmeyebilir. Çalıştırılan alıcılar, eşleşen intent-filter'ın android:Priority özelliğiyle kontrol edilebilir. Aynı önceliğe sahip alıcılar rastgele bir sırayla çalıştırılır.sendBroadcast(Intent)
yöntemi, yayınları tüm alıcılara tanımlanmamış bir sırada gönderir. Buna Normal Yayın deniyor. Bu daha verimlidir ancak alıcıların diğer alıcılardan gelen sonuçları okuyamayacağı, yayından alınan verileri dağıtamayacağı veya yayını iptal edemeyeceği anlamına gelir.
Aşağıdaki kod snippet'i, Intent oluşturup sendBroadcast(Intent)
yöntemini çağırarak yayının nasıl gönderileceğini göstermektedir.
Kotlin
Intent().also { intent -> intent.setAction("com.example.broadcast.MY_NOTIFICATION") intent.putExtra("data", "Nothing to see here, move along.") sendBroadcast(intent) }
Java
Intent intent = new Intent(); intent.setAction("com.example.broadcast.MY_NOTIFICATION"); intent.putExtra("data", "Nothing to see here, move along."); sendBroadcast(intent);
Yayın mesajı bir Intent
nesnesi içine sarmalanmış.
Niyetin işlem dizesi, uygulamanın Java paket adı söz dizimini sağlamalı ve yayın etkinliğini benzersiz bir şekilde tanımlamalıdır. putExtra(String, Bundle)
kullanarak amaca ek bilgiler ekleyebilirsiniz.
Amaçta setPackage(String)
yöntemini çağırarak bir yayını aynı kuruluştaki bir uygulama grubuyla da sınırlayabilirsiniz.
İzinlerle yayınları kısıtlama
İzinler, yayınları belirli izinlere sahip uygulama grubuyla kısıtlamanıza olanak tanır. Bir yayının göndereni veya alıcısı için kısıtlamalar uygulayabilirsiniz.
İzinlerle gönderiliyor
sendBroadcast(Intent, String)
veya sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
çağrısı yaptığınızda bir izin parametresi belirtebilirsiniz. Yalnızca manifest dosyalarında
Kotlin
sendBroadcast(Intent(BluetoothDevice.ACTION_FOUND), Manifest.permission.BLUETOOTH_CONNECT)
Java
sendBroadcast(new Intent(BluetoothDevice.ACTION_FOUND), Manifest.permission.BLUETOOTH_CONNECT)
Alıcı uygulama, yayını almak için aşağıda gösterildiği gibi izni istemelidir:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
BLUETOOTH_CONNECT
gibi mevcut bir sistem iznini belirtebilir veya <permission>
öğesiyle özel bir izin tanımlayabilirsiniz. İzinler ve güvenlikle ilgili genel bilgiler için Sistem İzinleri'ne göz atın.
İzinlerle alma
Bir yayın alıcısını kaydederken (manifest dosyanızdaki registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
ile veya <receiver>
etiketinde) bir izin parametresi belirtirseniz yalnızca manifest dosyalarında <uses-permission>
etiketiyle izin isteyen (ve daha sonra, tehlikeli olması durumunda daha sonra izin alan) yayıncılar alıcıya Intent gönderebilir.
Örneğin, alıcı uygulamanızın aşağıda gösterildiği gibi manifest beyan edilmiş bir alıcısı olduğunu varsayalım:
<receiver android:name=".MyBroadcastReceiver"
android:permission="android.permission.BLUETOOTH_CONNECT">
<intent-filter>
<action android:name="android.intent.action.ACTION_FOUND"/>
</intent-filter>
</receiver>
Veya alıcı uygulamanızın aşağıda gösterildiği gibi bağlama kayıtlı bir alıcısı var:
Kotlin
var filter = IntentFilter(Intent.ACTION_FOUND) registerReceiver(receiver, filter, Manifest.permission.BLUETOOTH_CONNECT, null )
Java
IntentFilter filter = new IntentFilter(Intent.ACTION_FOUND); registerReceiver(receiver, filter, Manifest.permission.BLUETOOTH_CONNECT, null );
Ardından, gönderen uygulamanın bu alıcılara yayın gönderebilmek için aşağıda gösterildiği gibi izni istemesi gerekir:
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
Güvenlikle ilgili olarak göz önünde bulundurulması gerekenler ve en iyi uygulamalar
Yayın gönderme ve almayla ilgili bazı güvenlik noktaları ve en iyi uygulamalar aşağıda verilmiştir:
Birçok uygulama, manifestlerinde aynı yayını almak üzere kaydolmuşsa bu durum, sistemin çok sayıda uygulama başlatmasına neden olarak hem cihaz performansını hem de kullanıcı deneyimini önemli ölçüde etkileyebilir. Bunu önlemek için manifest beyanı yerine bağlam kaydını kullanmayı tercih edin. Bazen Android sisteminin kendisi bağlama kayıtlı alıcıların kullanımını zorunlu kılar. Örneğin,
CONNECTIVITY_ACTION
yayını yalnızca bağlama kayıtlı alıcılara iletilir.Dolaylı bir niyet kullanarak hassas bilgileri yayınlamayın. Bilgiler, yayını almak için kaydolan tüm uygulamalar tarafından okunabilir. Yayınlarınızı kimlerin alabileceğini kontrol etmenin üç yolu vardır:
- Bir yayın gönderirken izin belirtebilirsiniz.
- Android 4.0 ve sonraki sürümlerde yayın gönderirken
setPackage(String)
ile bir paket belirtebilirsiniz. Sistem, yayını paketle eşleşen uygulama grubuyla kısıtlar.
Bir alıcıyı kaydettiğinizde, tüm uygulamalar uygulamanızın alıcısına potansiyel olarak kötü amaçlı yayınlar gönderebilir. Uygulamanızın aldığı yayınları sınırlamanın birkaç yolu vardır:
- Bir yayın alıcısını kaydederken bir izin belirtebilirsiniz.
- Manifest tarafından beyan edilen alıcılar için android:exported özelliğini manifest dosyasında "false" olarak ayarlayabilirsiniz. Alıcı, uygulama dışındaki kaynaklardan gelen yayınları almaz.
Yayın işlemlerinin ad alanı globaldir. İşlem adlarının ve diğer dizelerin sahip olduğunuz bir ad alanına yazıldığından emin olun. Aksi takdirde yanlışlıkla diğer uygulamalarla çakışabilir.
Alıcının
onReceive(Context, Intent)
yöntemi ana iş parçacığında çalıştığı için hızlı bir şekilde yürütülmeli ve geri dönmelidir. Uzun süre çalışan işler gerçekleştirmeniz gerekirseonReceive()
döndürüldükten sonra sistem tüm süreci sonlandırabileceğinden iş parçacıkları oluşturma veya arka plan hizmetlerini başlatma konusunda dikkatli olun. Daha fazla bilgi için İşlem durumu üzerindeki etkisi bölümüne bakın. Uzun süre çalışan işler gerçekleştirmek için şunları yapmanızı öneririz:- Alıcınızın
onReceive()
yöntemindegoAsync()
çağrılır veBroadcastReceiver.PendingResult
bir arka plan iş parçacığına iletilir. Bu sayede,onReceive()
ürününden döndükten sonra yayın etkin kalır. Ancak bu yaklaşımda bile sistem yayını çok hızlı bir şekilde (10 saniyeden kısa) bitirmenizi bekler. Ana iş parçacığında hata oluşmaması için işi başka bir iş parçacığına taşımanıza olanak tanır. JobScheduler
ile bir iş planlanıyor. Daha fazla bilgi için Akıllı İş Planlaması sayfasını inceleyin.
- Alıcınızın
Kullanıcı deneyimi rahatsız edici olduğundan, özellikle birden fazla alıcı varsa bu kuruluşlardan etkinlik başlatmayın. Bunun yerine bir bildirim görüntülemeyi düşünebilirsiniz.