Yayınlara genel bakış

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:

  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ö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:

  1. 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.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"
    
        // 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-alpha01"
    
        // 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")
    
        // 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-alpha01")
    
        // 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. 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çin onDestroy() 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çin onPause() 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 etiketiyle birlikte bu izni isteyen (ve daha sonra tehlikeliyse izni alan) 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ı 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önteminde goAsync() çağrılır ve BroadcastReceiver.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.
  • 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.