web-dev-qa-db-ja.com

ブロードキャストレシーバーを動的に登録できない-BluetoothDevice.ACTION_FOUND

Logクラスを使用してランタイムを追跡すると、onReceive()メソッドが呼び出されないことがわかります。なぜですか?

放送受信機を動的に登録

 private void discoverDevices () {
    Log.e("MOHAB","BEFORE ON RECEIVE");

     mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            Log.e("MOHAB","ON RECEIVE");
            String action = intent.getAction();
            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // Add the name and address to an array adapter to show in a ListView
                Bluetooth b = new Bluetooth(device.getName(),device.getAddress());
                list.add(b);
            }
        }
    };
    Log.e("MOHAB","create intentFilter");
    // Register the BroadcastReceiver
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy

}
13
Error

あなたが逃したのは、デバイスの回復を開始する必要があるということです

まず、Bluetoothアダプターを入手します

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

その後、あなたは電話で発見を開始します

mBtAdapter.startDiscovery();

ここでも詳細を読む必要があります。約cancelDiscovery()http://developer.Android.com/reference/Android/bluetooth/BluetoothAdapter.html#startDiscovery%28%29

P.S。また、公式ドキュメントによると、context.getSystemService(Context.BLUETOOTH_SERVICE)を使用してAPI 18以降でBluetoothAdapterを取得することをお勧めします。

ローカルのBluetoothアダプターを表すBluetoothAdapterを取得するには、JELLY_BEAN_MR1以下で実行しているときに、静的なgetDefaultAdapter()メソッドを呼び出します。 JELLY_BEAN_MR2以上で実行している場合は、BLUETOOTH_SERVICEを指定したgetSystemService(Class)で取得します。

編集:startDiscovery()への BLUETOOTH_ADMIN 権限が必要であることを思い出してください

8
Derek Fung

Android 6.0で始まる という事実は別として、_ACCESS_COARSE_LOCATION_ を受け取るには_ACTION_FOUND_権限が必要です(@としてsiniuxは既に言及されています)、別の関連するものがあり:

_ACCESS_COARSE_LOCATION_は、 危険な権限 の中にあり、実行時にユーザーから明示的に要求する必要があります(6.0で導入された別のセキュリティ改善)。

診断するには、_adb logcat | grep BroadcastQueue_を実行して、次のように表示できます。

_W/BroadcastQueue: Permission Denial: receiving Intent { 
    act=Android.bluetooth.device.action.FOUND flg=0x10 (has extras) } 
    to ProcessRecord{9007:com.examplepackage} (pid=9007, uid=10492) 
    requires Android.permission.ACCESS_COARSE_LOCATION due to sender
    com.Android.bluetooth (uid 1002)
_

したがって、MarshmallowでのBTデバイス検出の正しい手順は次のようになります。

  1. 通常のBluetoothアクセス許可とともに、マニフェストに_ACCESS_COARSE_LOCATION_アクセス許可の要件があります。

    _<uses-permission Android:name="Android.permission.BLUETOOTH" />
    <uses-permission Android:name="Android.permission.BLUETOOTH_ADMIN" />
    <uses-permission Android:name="Android.permission.ACCESS_COARSE_LOCATION" />
    _
  2. _ACCESS_COARSE_LOCATION_の実行時権限 があることを確認してください

    _protected void checkLocationPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
    
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                    REQUEST_COARSE_LOCATION);
        }
    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
        switch (requestCode) {
        case REQUEST_COARSE_LOCATION: {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                proceedDiscovery(); // --->
            } else {
                //TODO re-request
            }
            break;
        }
    }
    _

    }

  3. _ACTION_FOUND_のブロードキャストレシーバーを登録し、BluetoothAdapter.startDiscovery()を呼び出します。

    _protected void proceedDiscovery() {
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothDevice.ACTION_NAME_CHANGED);
        registerReceiver(mReceiver, filter);
    
        mBluetoothAdapter.startDiscovery();
    }
    _

_ACTION_NAME_CHANGED_の面白い点。 6.0はおおまかな場所の許可なしに_ACTION_FOUND_を提供しませんが、デバイスが検出されると、通常_ACTION_NAME_CHANGED_と連携して_ACTION_FOUND_イベントを取得します。つまり両方のイベントを取得するため、許可がなくても、ほぼ同じ動作で_ACTION_NAME_CHANGED_を処理できます。 (達人、私が間違っていれば訂正してください)

40
Ivan Bartsov

ブロードキャストレシーバーにも同様の問題がありました。それから私はこれを見つけました: https://developer.Android.com/about/versions/Marshmallow/Android-6.0-changes.html#behavior-hardware-id

基本的に、6.0では、Bluetoothデバイスをスキャンするには、位置情報の権限を使用する必要があります。

13
siniux

Android 6以降、1。)でACTION_FOUNDを機能させるには、専門家からの回答に従って次の点を確認してください。BLUETOOTHとBLUETOOTH_ADMINの権限を設定することに加えて、

<uses-permission Android:name="Android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission Android:name="Android.permission.ACCESS_FINE_LOCATION" />

時々これら二つは必要とされないかもしれませんが、それは私のために働きました。また、コードを使用して動的にユーザー権限を求める必要があります

int MY_PERMISSIONS_REQUEST = 200;
int permissions=ContextCompat.checkSelfPermission (this,Manifest.permission.ACCESS_FINE_LOCATION);
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                MY_PERMISSIONS_REQUEST);

次に、必要な操作を実行するためのコードを記述します。この直後に1つのstartDiscovery()メソッドを追加しました。確かに、これはあなたのために働くでしょう...ハッピーコーディング...

4
Jilson

あなたのコードがBluetoothデバイスを取得するのに正しいかどうか私は知りません。これがあなたのコードについて私が感じることです。関数内でのBroadcastReceiverの初期化と登録はお勧めできません。 onCreate()メソッドの外で行う必要があります。これがコードで行う必要があることです

このようにonCreate()で行わなければならないReciverの登録について

_registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
_

初期化または受信者を伴う

_private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("MOHAB","ON RECEIVE");
            String action = intent.getAction();
            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // Add the name and address to an array adapter to show in a ListView
                Bluetooth b = new Bluetooth(device.getName(),device.getAddress());
                list.add(b);
            }
        }
    };
_

onPause()で受信者の登録を解除することを忘れないでください

discoverDevices()では、その機能の呼び出しごとに、受信者によって追加されたデバイスのlistを返すだけです。

4
Jolson Da Costa

私が開発していたデバイス(Galaxy S4)は、ブロードキャストを受信し続ける前に再起動する必要があることがわかりました。

しかし、私の場合、私はそれらが(ランダムに?)受信を停止するまで問題なく受信し、私が何をしたにも関わらず(アプリを閉じ、アプリを再インストール)ブロードキャストが受信されませんでした。

0
TheIT

現在の担当者レベルではコメントできないため、これを回答として投稿します。

AndroidManifest.xmlにBluetoothパーミッションが含まれていますか?

<uses-permission Android:name="Android.permission.BLUETOOTH"/>
<uses-permission Android:name="Android.permission.BLUETOOTH_ADMIN"/>

そうでない場合は、それぞれの重要性を思い出せないため、それぞれを個別に試してみてください。

これらをお持ちの場合は、より多くのコードを含めてください。問題を診断できるようになります。

0
lkjsdf23