Android 藍芽音響開發

慢慢的燃燒發表於2017-03-30

完整demo地址:github

1.開啟藍芽:

      mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
      /**如果本地藍芽沒有開啟,則開啟*/
      if (!mBluetoothAdapter.isEnabled()) {
        // 我們通過startActivityForResult()方法發起的Intent將會在onActivityResult()回撥方法中獲取使用者的選擇,比如使用者單擊了Yes開啟,
        // 那麼將會收到RESULT_OK的結果,
        // 如果RESULT_CANCELED則代表使用者不願意開啟藍芽
        Intent mIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(mIntent, ENABLE_BLUE);
       } else {
           Toast.makeText(this, "藍芽已開啟", Toast.LENGTH_SHORT).show();
       }

監聽開啟的結果:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == ENABLE_BLUE) {
            if (resultCode == RESULT_OK) {
                Toast.makeText(this, "藍芽開啟成功", Toast.LENGTH_SHORT).show();
                getBondedDevices();
            } else if (resultCode == RESULT_CANCELED) {
                Toast.makeText(this, "藍芽開始失敗", Toast.LENGTH_SHORT).show();
            }
        } else {
        }
    }

2.關閉藍芽:

     /**關閉藍芽*/
     if (mBluetoothAdapter.isEnabled()) {
           mBluetoothAdapter.disable();
     }

3.設計藍芽為可見:

     Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
     intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 180);//180可見時間
     startActivity(intent);

4.收索藍芽:

註冊廣播監聽搜尋的結果:

     /**註冊搜尋藍芽receiver*/
     mFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
     mFilter.addAction(BluetoothDevice.ACTION_FOUND);
     mFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
     registerReceiver(mReceiver, mFilter);

開始的搜尋:

     // 如果正在搜尋,就先取消搜尋
     if (mBluetoothAdapter.isDiscovering()) {
         mBluetoothAdapter.cancelDiscovery();
     }
     // 開始搜尋藍芽裝置,搜尋到的藍芽裝置通過廣播返回
     mBluetoothAdapter.startDiscovery();

監聽搜尋的結果:

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            /** 搜尋到的藍芽裝置*/
            if (action.equals(BluetoothDevice.ACTION_FOUND)) {
                BluetoothDevice device = intent
                        .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // 搜尋到的不是已經配對的藍芽裝置
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    BlueDevice blueDevice = new BlueDevice();
                    blueDevice.setName(device.getName());
                    blueDevice.setAddress(device.getAddress());
                    blueDevice.setDevice(device);
                    setDevices.add(blueDevice);
                    blueAdapter.setSetDevices(setDevices);
                    blueAdapter.notifyDataSetChanged();
                    Log.d(MAINACTIVITY, "搜尋結果......"+device.getName());
                }
                /**當繫結的狀態改變時*/
            } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {


                /**搜尋完成*/
            } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
                setProgressBarIndeterminateVisibility(false);
                Log.d(MAINACTIVITY, "搜尋完成......");
                hideProgressDailog();
            }
        }
    };

5.配對藍芽:

配對工具類

    public class BlueUtils {
        public BlueUtils(BlueDevice blueDevice) {
            this.blueDevice = blueDevice;
        }
        /**
         * 配對
         */
        public void doPair() {
                if(null == mOthHandler){
                    HandlerThread handlerThread = new HandlerThread("other_thread");
                    handlerThread.start();
                    mOthHandler = new Handler(handlerThread.getLooper());
                }
                mOthHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        initSocket();   //取得socket
                        try {
                            socket.connect();   //請求配對
        //                      mAdapterManager.updateDeviceAdapter();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
        }

        /**
         * 取消藍芽配對
         * @param device
         */
        public static void unpairDevice(BluetoothDevice device) {
            try {
                Method m = device.getClass()
                        .getMethod("removeBond", (Class[]) null);
                m.invoke(device, (Object[]) null);
            } catch (Exception e) {
                Log.d("BlueUtils", e.getMessage());
            }
        }

        /**
         * 取得BluetoothSocket
         */
       private void initSocket() {
            BluetoothSocket temp = null;
            try {
                Method m = blueDevice.getDevice().getClass().getMethod("createRfcommSocket", new Class[] {int.class});
                temp = (BluetoothSocket) m.invoke(blueDevice.getDevice(), );
                //怪異錯誤: 直接賦值給socket,對socket操作可能出現異常,  要通過中間變數temp賦值給socket
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            socket = temp;
        }
    }

註冊監聽配對結果的廣播(使用同上面的註冊程式碼)

     /**註冊搜尋藍芽receiver*/
     mFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
     mFilter.addAction(BluetoothDevice.ACTION_FOUND);
     mFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
     registerReceiver(mReceiver, mFilter);

開始配對

    /**
     * 開始配對藍芽裝置
     *
     * @param blueDevice
     */
    private void startPariBlue(BlueDevice blueDevice) {
        BlueUtils blueUtils = new BlueUtils(blueDevice);
        blueUtils.doPair();
    }

監聽配對結果:(使用同上面的廣播接收者)

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            /** 搜尋到的藍芽裝置*/
            if (action.equals(BluetoothDevice.ACTION_FOUND)) {
                .....
                /**當繫結的狀態改變時*/
            } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                switch (device.getBondState()) {
                    case BluetoothDevice.BOND_BONDING:
                        Log.d(MAINACTIVITY, "正在配對......");
                        break;
                    case BluetoothDevice.BOND_BONDED:
                        Log.d(MAINACTIVITY, "完成配對");
                        hideProgressDailog();
                        /**開始連線*/
                        contectBuleDevices();
                        break;
                    case BluetoothDevice.BOND_NONE:
                        Log.d(MAINACTIVITY, "取消配對");
                        Toast.makeText(MainActivity.this,"成功取消配對",Toast.LENGTH_SHORT).show();
                        getBondedDevices();
                        break;
                    default:
                        break;
                }
                /**搜尋完成*/
            } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
                ....
            }
        }
    };

6.使用A2DP協議連線藍芽裝置:

連線裝置

    /**
     * 開始連線藍芽裝置
     */
    private void contectBuleDevices() {
        /**使用A2DP協議連線裝置*/
        mBluetoothAdapter.getProfileProxy(this, mProfileServiceListener, BluetoothProfile.A2DP);
    }

監聽連線的回撥

    /**
     * 連線藍芽裝置(通過監聽藍芽協議的服務,在連線服務的時候使用BluetoothA2dp協議)
     */
    private BluetoothProfile.ServiceListener mProfileServiceListener = new BluetoothProfile.ServiceListener() {
        @Override
        public void onServiceDisconnected(int profile) {
        }
        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            try {
                if (profile == BluetoothProfile.HEADSET) {
                    ....
                } else if (profile == BluetoothProfile.A2DP) {
                    /**使用A2DP的協議連線藍芽裝置(使用了反射技術呼叫連線的方法)*/
                    a2dp = (BluetoothA2dp) proxy;
                    if (a2dp.getConnectionState(currentBluetoothDevice) != BluetoothProfile.STATE_CONNECTED) {
                        a2dp.getClass()
                                .getMethod("connect", BluetoothDevice.class)
                                .invoke(a2dp, currentBluetoothDevice);
                        Toast.makeText(MainActivity.this,"請播放音樂",Toast.LENGTH_SHORT).show();
                        getBondedDevices();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

7.新增許可權

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

8.開啟樂庫播放音樂

9.Android 6.0的系統需要動態新增許可權才能搜尋出藍芽裝置

Android 6.0的系統需要動態新增許可權

    /**判斷手機系統的版本*/
    if (Build.VERSION.SDK_INT >= 6.0) {//Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
            if(ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)!=PackageManager.PERMISSION_GRANTED){
                /**動態新增許可權:ACCESS_FINE_LOCATION*/
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        MY_PERMISSION_REQUEST_CONSTANT);
            }
        }

請求許可權的回撥

    /**請求許可權的回撥:這裡判斷許可權是否新增成功*/
     /**請求許可權的回撥:這裡判斷許可權是否新增成功*/
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSION_REQUEST_CONSTANT: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.i("main","新增許可權成功");
                }
                return;
            }
        }
    }

相關文章