Yayınlara genel bakış

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:

  1. 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.

  2. BroadcastReceiver alt sınıfını oluşturun ve onReceive(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:

  1. 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")
    }
    
  2. BroadcastReceiver örneği oluşturun:

    Kotlin

    val br: BroadcastReceiver = MyBroadcastReceiver()
    

    Java

    BroadcastReceiver br = new MyBroadcastReceiver();
    
  3. IntentFilter örneği oluşturun:

    Kotlin

    val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
    

    Java

    IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
    
  4. 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ı dinliyorsa RECEIVER_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;
    }
    
  5. registerReceiver() numaralı telefonu arayarak alıcıyı kaydedin:

    Kotlin

    ContextCompat.registerReceiver(context, br, filter, receiverFlags)
    

    Java

    ContextCompat.registerReceiver(context, br, filter, receiverFlags);
    
  6. 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çin onDestroy() uygulamasında kaydınızı iptal etmeniz gerekir. onResume() bölgesinde bir alıcıyı kaydederseniz birden fazla kez kaydedilmesini önlemek için onPause() 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 etiketiyle bu izni isteyen (ve tehlikeli olması durumunda daha sonra izin verilen) alıcılar yayını alabilir. Örneğin, aşağıdaki kod bir yayın gönderir:

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 gerekirse onReceive() 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önteminde goAsync() çağrılır ve BroadcastReceiver.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.
  • 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.