Android uygulamaları, publish-subscribe tasarım kalıbına benzer şekilde Android sisteminden ve diğer Android uygulamalarından yayın mesajları gönderebilir veya alabilir. Bu yayınlar, ilgilenilen bir etkinlik gerçekleştiğinde gönderilir. Örneğin, Android sistemi, sistemin başlatılması veya cihazın şarj edilmeye başlaması gibi çeşitli sistem etkinlikleri gerçekleştiğinde yayınlar gönderir. Uygulamalar ayrıca, örneğin, diğer uygulamaları ilgilerini çekebilecek bir şey (örneğin, bazı yeni veriler indirildi) konusunda bildirmek 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ı söz konusu yayın türünü almak için abone olan uygulamalara otomatik olarak 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 işleri arka planda çalıştırma imkanını kötüye kullanmamaya dikkat etmelisiniz. Bu durum, sistem performansının yavaşlamasına neden olabilir.
Sistem yayınları hakkında
Sistem, uçak moduna girip çıkma gibi çeşitli sistem olayları gerçekleştiğinde sistem yayınları otomatik olarak 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 ekstra Boole değeri içerir.
Niyetleri okuma ve bir amaçtan işlem dizesini alma 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 işleminin kendisiyle ilişkilendirilmiş
sabit bir alanı vardır. Örneğin, ACTION_AIRPLANE_MODE_CHANGED
sabitinin değeri android.intent.action.AIRPLANE_MODE
olur. Her bir yayın eylemine ilişkin belgeler,
ilgili sabit alanda mevcuttur.
Sistem yayınlarındaki değişiklikler
Android platformu geliştikçe, sistem yayınlarının davranışı periyodik olarak değişir. Tüm Android sürümlerini desteklemek için aşağıdaki değişiklikleri aklınızda bulundurun.
Android 14
Uygulamalar önbelleğe alınmış durumdayken yayın dağıtımı, sistem durumu için optimize edilmiştir. Ö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 süreç yaşam döngüsüne dönüştüğünde sistem, ertelenmiş tüm yayınları sunar.
Manifest'te beyan edilen önemli yayınlar, yayınlanmak üzere uygulamaları geçici olarak önbelleğe alınmış durumdan kaldırır.
Android 9
Android 9'dan itibaren (API düzeyi 28) itibaren 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üklenirse 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 beyan edilen alıcılara ek kısıtlamalar uygular.
Uygulamanız Android 8.0 veya sonraki bir sürümü hedefliyorsa çoğu örtülü yayın (özel olarak uygulamanızı hedeflemeyen yayınlar) için bir alıcı bildirmek üzere manifest'i kullanamazsınız. Kullanıcı, uygulamanızı etkin bir şekilde 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 dosyasında alıcı tanımlama işlevi işe yaramaz.
Yayın alınıyor
Uygulamalar, yayınları iki şekilde alabilir: manifestoyu beyan eden alıcılar ve bağlama kayıtlı alıcılar.
Manifest dosyası tarafından beyan edilen alıcılar
Manifest'inizde bir yayın alıcısı belirtirseniz sistem, yayın gönderildiğinde 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örüntüler: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. Daha sonra alıcı, uygulamanıza ayrı bir giriş noktası haline gelir. Bu da, sistemin uygulamayı başlatabileceği ve uygulama şu anda çalışmıyorsa yayını sunabileceği anlamına gelir.
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 yapıldığı süre boyunca geçerlidir. Kodunuz bu yöntemden döndürüldüğü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 sonraki bir sürümünü ekleyin:
Modern
dependencies { def core_version = "1.13.1" // 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" // To test the Animator APIs androidTestImplementation "androidx.core:core-animation-testing:1.0.0" // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation "androidx.core:core-performance:1.0.0" // 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.1.0" // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation "androidx.core:core-splashscreen:1.2.0-alpha01" }
Kotlin
dependencies { val core_version = "1.13.1" // 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") // To test the Animator APIs androidTestImplementation("androidx.core:core-animation-testing:1.0.0") // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation("androidx.core:core-performance:1.0.0") // 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.1.0") // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation("androidx.core:core-splashscreen:1.2.0-alpha01") }
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);
Anons 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.Nerelerde alıcı kaydı yaptığınıza ve alıcının kaydını iptal ettiğinize dikkat edin. Örneğin,
onCreate(Bundle)
uygulamasında bir alıcıyı etkinliğin bağlamını kullanarak kaydederseniz alıcının etkinlik bağlamından sızdırılmasını önlemek içinonDestroy()
içinde kaydını silmeniz gerekir.onResume()
bölgesinde bir alıcıyı kaydederseniz bir alıcının birden çok kez kaydedilmesini önlemek içinonPause()
uygulamasındaki kaydını iptal etmeniz gerekir (Duraklatıldığında yayın almak istemezseniz bu, gereksiz sistem ek yükünü azaltabilir).onSaveInstanceState(Bundle)
kaydını iptal etmeyin. Kullanıcı, geçmiş yığınında geri giderse bu çağrılmaz.
İşlem durumu üzerindeki etkiler
BroadcastReceiver
ürününüzün çalışıp çalışmayacağı, içerdiği işlemi etkileyip etkilemediği. Bu durum, sistem öldürme 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.
BroadcastRecipientr onReceive()
tarihinden sonra devre dışı bırakılır. Alıcının ana makine işlemi, yalnızca uygulama bileşenleri kadar önemlidir. Bu işlem yalnızca manifest beyan edilen bir alıcı barındırıyorsa (kullanıcının daha önce hiç etkileşimde bulunmadığı veya hiç etkileşimde bulunmadığı uygulamalar için sık karşılaşılan bir durum) sistem, diğer kritik süreçlere kaynak sağlamak 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
ayarlayın.
Böylece sistem, sürecin hâlâ çalıştığını bilir.
Arka Planda Çalışmaya Genel Bakış daha fazla ayrıntı sağlar.
Yayın gönderme
Android, uygulamaların yayın göndermesi için üç yol sağlar:
sendOrderedBroadcast(Intent, String)
yöntemi, yayınları her defasında bir alıcıya gönderir. Her alıcı sırayla yürüttükçe, bir sonucu bir sonraki alıcıya yayabilir veya diğer alıcılara iletilmemesi için yayını tamamen iptal edebilir. Çalıştırılan sıra alıcıları, eşleşen intent-filtresinin 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 adı verilir. Bu daha verimlidir ancak alıcıların diğer alıcılardan gelen sonuçları okuyamayacağı, yayından alınan verileri yayamayacağı veya yayını durduramayacağı 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 paketi 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önderme
sendBroadcast(Intent, String)
veya sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
çağırırken 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ı uygulamanın, yayını almak için aşağıda gösterilen izni istemesi gerekir:
<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 genel olarak güvenlik hakkında bilgi edinmek için Sistem İzinleri'ne bakın.
İzinlerle alma
Bir yayın alıcısını kaydederken (manifestinizde registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
veya <receiver>
etiketiyle) bir izin parametresi belirtirseniz yalnızca manifest dosyalarında <uses-permission>
etiketiyle izin isteyen (ve daha sonra tehlikeliyse izni alan) yayıncılar alıcıya bir Niyet 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, bu alıcılara yayın gönderebilmek için gönderen uygulamanın aşağıda gösterilen şekilde 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 şunlardır:
Çok sayıda uygulama manifest'lerinde aynı yayını almak üzere kaydolmuşsa bu durum, sistemin çok sayıda uygulama başlatmasına yol açarak 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.Hassas bilgileri dolaylı bir amaç kullanarak 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ı kaydettiğinizde, her uygulama kendi alıcısına kötü amaçlı olabilecek yayınlar gönderebilir. Uygulamanızın alacağı yayınları sınırlandırmanın birkaç yolu vardır:
- Bir yayın alıcısını kaydederken izin belirtebilirsiniz.
- Manifest'te beyan edilen alıcılar için, manifest'te android:exported özelliğini "false" olarak ayarlayabilirsiniz. Alıcı, uygulama dışındaki kaynaklardan yayınları almaz.
Yayın işlemlerinin ad alanı geneldir. İş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 gerekiyorsa sistem,onReceive()
geri döndükten sonra 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üreli çalışma gerçekleştirmek için aşağıdakileri 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 şekilde,onReceive()
konumundan döndüğünüzde 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ığının bozulmasını önlemek için işi başka bir iş parçacığına taşımanıza olanak tanır. JobScheduler
ile iş planlama. Daha fazla bilgi için Akıllı İş Planlaması sayfasına göz atın.
- Alıcınızın
Kullanıcı deneyimi sarsıcı olduğundan, özellikle birden fazla alıcı varsa yayın alıcılarından etkinlik başlatmayın. Bunun yerine bir bildirim görüntülemeyi deneyin.