Tamamlayıcı cihaz eşleme

Android 8.0 (API düzeyi 26) ve sonraki sürümleri çalıştıran cihazlarda, tamamlayıcı cihaz eşleme işlevi ACCESS_FINE_LOCATION izni gerekmeksizin uygulamanız adına yakındaki cihazların Bluetooth veya kablosuz ağ taramasını gerçekleştirir. Bu, kullanıcı gizliliği korumalarını en üst düzeye çıkarmaya yardımcı olur. Eşlenen cihaz, uygulamayı arka planda başlatmak için REQUEST_COMPANION_RUN_IN_BACKGROUND ve REQUEST_COMPANION_USE_DATA_IN_BACKGROUND izinlerinden yararlanabilir. BLE özellikli bir akıllı saat gibi tamamlayıcı cihazın ilk yapılandırmasını gerçekleştirmek için bu yöntemi kullanın. Ayrıca, tamamlayıcı cihaz eşleme için Konum Hizmetleri'nin etkinleştirilmesi gerekir.

Tamamlayıcı cihaz eşleme kendi başına bağlantı oluşturmaz. Bluetooth ve kablosuz bağlantı API'leri bağlantı kurar. Tamamlayıcı cihaz eşleme özelliği de sürekli taramayı etkinleştirmez.

Kullanıcı listeden bir cihaz seçebilir ve uygulamaya erişmesi için izin verebilir. Uygulamayı kaldırırsanız veya disassociate() numaralı telefonu ararsanız bu izinler iptal edilir. Kullanıcının artık ihtiyaç duymadığı durumlarda (örneğin, oturumu kapattığında veya bağlı cihazları kaldırdığında) kendi ilişkilendirmelerini temizlemek bir uygulamadır.

Tamamlayıcı cihaz eşlemesini uygulayın

Tamamlayıcı bir cihazla bağlantı kurup yönetmek için şunu kullanın: CompanionDeviceManager. Bu bölümde, uygulamanızı Bluetooth, BLE ve kablosuz ağ üzerinden tamamlayıcı cihazlarla eşlediğinizde eşleme isteği iletişim kutunuzu nasıl özelleştireceğiniz açıklanmaktadır.

Tamamlayıcı cihazları belirtin

Aşağıdaki kod örneğinde, <uses-feature> işaretinin manifest dosyasına nasıl ekleneceği gösterilmektedir. Bu, sisteme uygulamanızın tamamlayıcı cihazlar kurmayı amaçladığını bildirir.

<uses-feature android:name="android.software.companion_device_setup"/>

Cihazları türe göre listeleme

Sağladığınız filtreyle eşleşen tüm olası tamamlayıcı cihazları görüntüleyebilir veya görüntülemeyi tek bir seçenekle sınırlandırabilirsiniz (Şekil 1'de gösterilmiştir). Uygulamanızın ne tür cihazlar aradığını belirten bir filtre oluşturarak veya setSingleDevice() özelliğini true olarak ayarlayarak (Şekil 2'de gösterilmiştir) bunu yapılandırabilirsiniz.

Tamamlayıcı Cihaz Eşleme ekranı, tek bir eşleme seçeneğiyle
    sınırlıdır.
Şekil 1. Tamamlayıcı Cihaz Eşleme ekranı, tek bir eşleme seçeneğiyle sınırlıdır.
Tamamlayıcı Cihaz Eşleme ekranı, profili olmayan tek bir eşleme seçeneğiyle sınırlıdır.
Şekil 2. Tamamlayıcı Cihaz Eşleme ekranı, profili olmayan tek bir eşleme seçeneğiyle sınırlıdır.

İstek iletişim kutunuzda gösterilen tamamlayıcı cihazların listesine filtre uygulamak için Bluetooth'un açık olup olmadığını veya kablosuz bağlantının açık olup olmadığını kontrol edin. Bağlantı etkinleştirildikten sonra DeviceFilter ekleyebilirsiniz. Aşağıdaki DeviceFilter alt sınıfları, uygulamanızın bir bağlantı türüne göre ilişkilendirebileceği cihaz türlerini belirtir:

Üç alt sınıfın tümü, filtrelerin yapılandırmasını kolaylaştıran oluşturuculara sahiptir. Aşağıdaki örnekte, bir cihaz BluetoothDeviceFilter özelliğine sahip bir Bluetooth cihazı tarar.

Kotlin

val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder()
        // Match only Bluetooth devices whose name matches the pattern.
        .setNamePattern(Pattern.compile("My device"))
        // Match only Bluetooth devices whose service UUID matches this pattern.
        .addServiceUuid(ParcelUuid(UUID(0x123abcL, -1L)), null)
        .build()

Java

BluetoothDeviceFilter deviceFilter = new BluetoothDeviceFilter.Builder()
        // Match only Bluetooth devices whose name matches the pattern.
        .setNamePattern(Pattern.compile("My device"))
        // Match only Bluetooth devices whose service UUID matches this pattern.
        .addServiceUuid(new ParcelUuid(new UUID(0x123abcL, -1L)), null)
        .build();

Cihaz yöneticisinin ne tür bir cihaz aranacağını belirleyebilmesi için DeviceFilter değerini AssociationRequest olarak ayarlayın.

Kotlin

val pairingRequest: AssociationRequest = AssociationRequest.Builder()
        // Find only devices that match this request filter.
        .addDeviceFilter(deviceFilter)
        // Stop scanning as soon as one device matching the filter is found.
        .setSingleDevice(true)
        .build()

Java

AssociationRequest pairingRequest = new AssociationRequest.Builder()
        // Find only devices that match this request filter.
        .addDeviceFilter(deviceFilter)
        // Stop scanning as soon as one device matching the filter is found.
        .setSingleDevice(true)
        .build();

Bir AssociationRequest başlattıktan sonra CompanionDeviceManager üzerinde associate() işlevini çalıştırın. associate() işlevi, eşleme isteği nesnesini ve geri çağırmayı üstlenir. Geri çağırma işlevleri, bir uygulamanın bir cihazı bulduğunda ve kullanıcının seçimini girmesi için bir iletişim kutusu başlatmaya hazır olduğunda bunu belirtir. Bir uygulama herhangi bir cihaz bulamazsa geri arama bir hata mesajı döndürür.

Android 13 (API düzeyi 33) ve sonraki sürümleri çalıştıran cihazlarda:

Kotlin

val deviceManager =
  requireContext().getSystemService(Context.COMPANION_DEVICE_SERVICE)

val executor: Executor =  Executor { it.run() }

deviceManager.associate(pairingRequest,
    executor,
    object : CompanionDeviceManager.Callback() {
    // Called when a device is found. Launch the IntentSender so the user
    // can select the device they want to pair with.
    override fun onAssociationPending(intentSender: IntentSender) {
        intentSender?.let {
             startIntentSenderForResult(it, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0)
        }
    }

    override fun onAssociationCreated(associationInfo: AssociationInfo) {
        // The association is created.
    }

    override fun onFailure(errorMessage: CharSequence?) {
        // Handle the failure.
     }
})

Java

CompanionDeviceManager deviceManager =
        (CompanionDeviceManager) getSystemService(Context.COMPANION_DEVICE_SERVICE);

Executor executor = new Executor() {
            @Override
            public void execute(Runnable runnable) {
                runnable.run();
            }
        };
deviceManager.associate(pairingRequest, new CompanionDeviceManager.Callback() {
    executor,
    // Called when a device is found. Launch the IntentSender so the user can
    // select the device they want to pair with.
    @Override
    public void onDeviceFound(IntentSender chooserLauncher) {
        try {
            startIntentSenderForResult(
                    chooserLauncher, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0
            );
        } catch (IntentSender.SendIntentException e) {
            Log.e("MainActivity", "Failed to send intent");
        }
    }

    @Override
    public void onAssociationCreated(AssociationInfo associationInfo) {
        // The association is created.
    }

    @Override
    public void onFailure(CharSequence errorMessage) {
        // Handle the failure.
    });

Android 12L (API düzeyi 32) ve önceki sürümleri (kullanımdan kaldırıldı) çalıştıran cihazlarda:

Kotlin

val deviceManager =
      requireContext().getSystemService(Context.COMPANION_DEVICE_SERVICE)

deviceManager.associate(pairingRequest,
    object : CompanionDeviceManager.Callback() {
        // Called when a device is found. Launch the IntentSender so the user
        // can select the device they want to pair with.
        override fun onDeviceFound(chooserLauncher: IntentSender) {
            startIntentSenderForResult(chooserLauncher,
                SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0)
        }

        override fun onFailure(error: CharSequence?) {
            // Handle the failure.
        }
    }, null)

Java

CompanionDeviceManager deviceManager =
        (CompanionDeviceManager) getSystemService(Context.COMPANION_DEVICE_SERVICE);
deviceManager.associate(pairingRequest, new CompanionDeviceManager.Callback() {
    // Called when a device is found. Launch the IntentSender so the user can
    // select the device they want to pair with.
    @Override
    public void onDeviceFound(IntentSender chooserLauncher) {
        try {
            startIntentSenderForResult(
                    chooserLauncher, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0
            );
        } catch (IntentSender.SendIntentException e) {
            Log.e("MainActivity", "Failed to send intent");
        }
    }

    @Override
    public void onFailure(CharSequence error) {
        // Handle the failure.
    }
}, null);

Kullanıcıların, bağlanmak istedikleri cihaz türlerini seçmelerine olanak tanımak için onAssociationPending() işlevinde intentSender parametresiyle bir tercih etkinliği başlatın. Bu işlemin sonuçları, tercihler etkinliğinizin onActivityResult() işlevindeki parçaya geri gönderilir. Bu, kullanıcı sonuca göre bir seçim yaptığında sizi bilgilendirir. Ardından, seçilen cihaza erişebilirsiniz. Kullanıcı bir Bluetooth cihazı seçtiğinde gönderilen sonuç bir BluetoothDevice nesnesi olur. Benzer şekilde, onAssociationPending() işlevi kullanıcının bir Bluetooth LE cihaz seçtiğini algıladığında bir android.bluetooth.le.ScanResult nesnesi görüntülenir. Kablosuz cihazlar için bir android.net.wifi.ScanResult nesnesi görürsünüz.

Kotlin

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    when (requestCode) {
        SELECT_DEVICE_REQUEST_CODE -> when(resultCode) {
            Activity.RESULT_OK -> {
                // The user chose to pair the app with a Bluetooth device.
                val deviceToPair: BluetoothDevice? =
data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE)
                deviceToPair?.let { device ->
                    device.createBond()
                    // Continue to interact with the paired device.
                }
            }
        }
        else -> super.onActivityResult(requestCode, resultCode, data)
    }
}

Java

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    if (resultCode != Activity.RESULT_OK) {
        return;
    }
    if (requestCode == SELECT_DEVICE_REQUEST_CODE && data != null) {
        BluetoothDevice deviceToPair =
data.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE);
        if (deviceToPair != null) {
            deviceToPair.createBond();
            // Continue to interact with the paired device.
        }
    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}

Tamamlayıcı cihaz eşlemesini, cihazları belirtebilen ve türe göre listeleyebilen filtrelerle uygulamak için aşağıdaki örnekleri inceleyin:

Android 13 (API düzeyi 33) ve sonraki sürümleri çalıştıran cihazlarda:

Kotlin

private const val SELECT_DEVICE_REQUEST_CODE = 0

class MainActivity : AppCompatActivity() {

    private val deviceManager: CompanionDeviceManager by lazy {
        getSystemService(Context.COMPANION_DEVICE_SERVICE) as CompanionDeviceManager
    }
    val mBluetoothAdapter: BluetoothAdapter by lazy { 
        val java = BluetoothManager::class.java
        getSystemService(java)!!.adapter }
    val executor: Executor =  Executor { it.run() }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // To skip filters based on names and supported feature flags (UUIDs),
        // omit calls to setNamePattern() and addServiceUuid()
        // respectively, as shown in the following  Bluetooth example.
        val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder()
            .setNamePattern(Pattern.compile("My device"))
            .addServiceUuid(ParcelUuid(UUID(0x123abcL, -1L)), null)
            .build()

        // The argument provided in setSingleDevice() determines whether a single
        // device name or a list of them appears.
        val pairingRequest: AssociationRequest = AssociationRequest.Builder()
            .addDeviceFilter(deviceFilter)
            .setSingleDevice(true)
            .build()

        // When the app tries to pair with a Bluetooth device, show the
        // corresponding dialog box to the user.
        deviceManager.associate(pairingRequest,
            executor,
            object : CompanionDeviceManager.Callback() {
                // Called when a device is found. Launch the IntentSender so the user
                // can select the device they want to pair with.
                override fun onAssociationPending(intentSender: IntentSender) {
                intentSender?.let {
                    startIntentSenderForResult(it, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0)
              }
            }

             override fun onAssociationCreated(associationInfo: AssociationInfo) {
                 // AssociationInfo object is created and get association id and the 
                 // macAddress.
                 var associationId: int = associationInfo.id
                 var macAddress: MacAddress = associationInfo.deviceMacAddress
             }
             override fun onFailure(errorMessage: CharSequence?) {
                // Handle the failure.
            }
    )

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        when (requestCode) {
            SELECT_DEVICE_REQUEST_CODE -> when(resultCode) {
                Activity.RESULT_OK -> {
                    // The user chose to pair the app with a Bluetooth device.
                    val deviceToPair: BluetoothDevice? =
                        data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE)
                    deviceToPair?.let { device ->
                        device.createBond()
                        // Maintain continuous interaction with a paired device.
                    }
                }
            }
            else -> super.onActivityResult(requestCode, resultCode, data)
        }
    }
}

Java

class MainActivityJava extends AppCompatActivity {

    private static final int SELECT_DEVICE_REQUEST_CODE = 0;
    Executor executor = new Executor() {
        @Override
        public void execute(Runnable runnable) {
            runnable.run();
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        CompanionDeviceManager deviceManager =
            (CompanionDeviceManager) getSystemService(
                Context.COMPANION_DEVICE_SERVICE
            );

        // To skip filtering based on name and supported feature flags,
        // do not include calls to setNamePattern() and addServiceUuid(),
        // respectively. This example uses Bluetooth.
        BluetoothDeviceFilter deviceFilter =
            new BluetoothDeviceFilter.Builder()
                .setNamePattern(Pattern.compile("My device"))
                .addServiceUuid(
                    new ParcelUuid(new UUID(0x123abcL, -1L)), null
                )
                .build();

        // The argument provided in setSingleDevice() determines whether a single
        // device name or a list of device names is presented to the user as
        // pairing options.
        AssociationRequest pairingRequest = new AssociationRequest.Builder()
            .addDeviceFilter(deviceFilter)
            .setSingleDevice(true)
            .build();

        // When the app tries to pair with the Bluetooth device, show the
        // appropriate pairing request dialog to the user.
        deviceManager.associate(pairingRequest, new CompanionDeviceManager.Callback() {
            executor,
           // Called when a device is found. Launch the IntentSender so the user can
           // select the device they want to pair with.
           @Override
           public void onDeviceFound(IntentSender chooserLauncher) {
               try {
                   startIntentSenderForResult(
                       chooserLauncher, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0
                   );
               } catch (IntentSender.SendIntentException e) {
                   Log.e("MainActivity", "Failed to send intent");
               }
           }

          @Override
          public void onAssociationCreated(AssociationInfo associationInfo) {
                 // AssociationInfo object is created and get association id and the
                 // macAddress.
                 int associationId = associationInfo.getId();
                 MacAddress macAddress = associationInfo.getDeviceMacAddress();
          }

          @Override
          public void onFailure(CharSequence errorMessage) {
             // Handle the failure.
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (resultCode != Activity.RESULT_OK) {
            return;
        }
        if (requestCode == SELECT_DEVICE_REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK && data != null) {
                BluetoothDevice deviceToPair = data.getParcelableExtra(
                    CompanionDeviceManager.EXTRA_DEVICE
                );

                if (deviceToPair != null) {
                    deviceToPair.createBond();
                    // ... Continue interacting with the paired device.
                }
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }
}

Android 12L (API düzeyi 32) ve önceki sürümleri (kullanımdan kaldırıldı) çalıştıran cihazlarda:

Kotlin

private const val SELECT_DEVICE_REQUEST_CODE = 0

class MainActivity : AppCompatActivity() {

    private val deviceManager: CompanionDeviceManager by lazy {
        getSystemService(Context.COMPANION_DEVICE_SERVICE) as CompanionDeviceManager
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // To skip filters based on names and supported feature flags (UUIDs),
        // omit calls to setNamePattern() and addServiceUuid()
        // respectively, as shown in the following  Bluetooth example.
        val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder()
            .setNamePattern(Pattern.compile("My device"))
            .addServiceUuid(ParcelUuid(UUID(0x123abcL, -1L)), null)
            .build()

        // The argument provided in setSingleDevice() determines whether a single
        // device name or a list of them appears.
        val pairingRequest: AssociationRequest = AssociationRequest.Builder()
            .addDeviceFilter(deviceFilter)
            .setSingleDevice(true)
            .build()

        // When the app tries to pair with a Bluetooth device, show the
        // corresponding dialog box to the user.
        deviceManager.associate(pairingRequest,
            object : CompanionDeviceManager.Callback() {

                override fun onDeviceFound(chooserLauncher: IntentSender) {
                    startIntentSenderForResult(chooserLauncher,
                        SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0)
                }

                override fun onFailure(error: CharSequence?) {
                    // Handle the failure.
                }
            }, null)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        when (requestCode) {
            SELECT_DEVICE_REQUEST_CODE -> when(resultCode) {
                Activity.RESULT_OK -> {
                    // The user chose to pair the app with a Bluetooth device.
                    val deviceToPair: BluetoothDevice? =
                        data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE)
                    deviceToPair?.let { device ->
                        device.createBond()
                        // Maintain continuous interaction with a paired device.
                    }
                }
            }
            else -> super.onActivityResult(requestCode, resultCode, data)
        }
    }
}

Java

class MainActivityJava extends AppCompatActivity {

    private static final int SELECT_DEVICE_REQUEST_CODE = 0;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        CompanionDeviceManager deviceManager =
            (CompanionDeviceManager) getSystemService(
                Context.COMPANION_DEVICE_SERVICE
            );

        // To skip filtering based on name and supported feature flags,
        // don't include calls to setNamePattern() and addServiceUuid(),
        // respectively. This example uses Bluetooth.
        BluetoothDeviceFilter deviceFilter = 
            new BluetoothDeviceFilter.Builder()
                .setNamePattern(Pattern.compile("My device"))
                .addServiceUuid(
                    new ParcelUuid(new UUID(0x123abcL, -1L)), null
                )
                .build();

        // The argument provided in setSingleDevice() determines whether a single
        // device name or a list of device names is presented to the user as
        // pairing options.
        AssociationRequest pairingRequest = new AssociationRequest.Builder()
            .addDeviceFilter(deviceFilter)
            .setSingleDevice(true)
            .build();

        // When the app tries to pair with the Bluetooth device, show the
        // appropriate pairing request dialog to the user.
        deviceManager.associate(pairingRequest,
            new CompanionDeviceManager.Callback() {
                @Override
                public void onDeviceFound(IntentSender chooserLauncher) {
                    try {
                        startIntentSenderForResult(chooserLauncher,
                            SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0);
                    } catch (IntentSender.SendIntentException e) {
                        // failed to send the intent
                    }
                }

                @Override
                public void onFailure(CharSequence error) {
                    // handle failure to find the companion device
                }
            }, null);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (requestCode == SELECT_DEVICE_REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK && data != null) {
                BluetoothDevice deviceToPair = data.getParcelableExtra(
                    CompanionDeviceManager.EXTRA_DEVICE
                );

                if (deviceToPair != null) {
                    deviceToPair.createBond();
                    // ... Continue interacting with the paired device.
                }
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }
}

Tamamlayıcı cihaz profilleri

Android 12 (API düzeyi 31) ve sonraki sürümlerdeki iş ortağı uygulamaları, bir saate bağlanırken tamamlayıcı cihaz profillerini kullanabilir. Daha fazla bilgi için Wear OS'te izin isteme rehberine bakın.

Tamamlayıcı uygulamaları uyanık tutun

Android 12 (API düzeyi 31) ve sonraki sürümlerde, tamamlayıcı cihaz kapsama alanındayken tamamlayıcı uygulamanızın çalışmaya devam etmesine yardımcı olan ek API'ler kullanabilirsiniz. Bu API'ler aşağıdakileri yapmanıza imkan tanır: