需要3個權限:
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.bluetooth.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="open"
android:text="直接打開藍牙" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="request"
android:text="請求用戶打開藍牙" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="close"
android:text="關閉藍牙" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="setName"
android:text="設置藍牙名稱" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="discover"
android:text="打開可被發現" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="getBound"
android:text="獲取已配對的設備" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="scan"
android:text="開始掃描" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="startServer"
android:text="建立連接" />
</LinearLayout>
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
package com.example.bluetooth;
import android.Manifest;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
BluetoothAdapter bluetoothAdapter;
ListView lv;
// 所有掃描的藍牙名稱的集合
List<String> deviceNames = new ArrayList<>();
// 所有掃描的藍牙設備的集合
List<BluetoothDevice> devices = new ArrayList<>();
ArrayAdapter<String> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 獲取藍牙適配器
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 找到ListView控件
lv = (ListView) findViewById(R.id.lv);
// 創建一個適配器
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, deviceNames);
lv.setAdapter(adapter);
// 設置ListView的點擊事件去請求服務端
lv.setOnItemClickListener(this);
}
// 點擊按鈕直接打開藍牙
public void open(View view) {
// 直接打開藍牙(不推薦使用的)第一次打開需要獲取權限 要添加權限 BLUETOOTH_ADMIN 和 BLUETOOTH
bluetoothAdapter.enable();
}
// 點擊按鈕請求用戶打開藍牙
public void request(View view) {
// 請求用戶打開藍牙(推薦使用的方法)每次打開都需要獲取權限
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(intent);
}
// 點擊按鈕關閉藍牙
public void close(View view) {
// 關閉直接調用disable方法
bluetoothAdapter.disable();
}
// 點擊按鈕設置藍牙名稱
public void setName(View view) {
// 創建一個對話框
AlertDialog.Builder builder = new AlertDialog.Builder(this);
// 創建一個輸入控件
final EditText et = new EditText(this);
// 顯示藍牙名稱
et.setText(bluetoothAdapter.getName());
// 把輸入控件設置到對話框內
builder.setView(et);
// 設置對話框標題
builder.setTitle("設置藍牙名稱");
// 設置取消確定按鈕
builder.setNegativeButton("取消", null);
builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String name = et.getText().toString();
if (TextUtils.isEmpty(name)) {
Toast.makeText(MainActivity.this, "藍牙名稱不能爲空", Toast.LENGTH_SHORT).show();
} else {
bluetoothAdapter.setName(name);
}
}
}).create().show();
}
// 點擊按鈕可被發現或掃描
public void discover(View view) {
// 使用意圖來操作 可被發現
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
// 可被發現的默認時間是120秒(可以被改,這裏改成600秒)
intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 600);
startActivity(intent);
}
// 點擊按鈕獲取已配對過的設備
public void getBound(View view) {
// 獲取已配對的藍牙設備
Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();
// set集合裏面去數據用迭代器或者foreach,不能使用for循環,因爲沒有索引號
for (BluetoothDevice bondedDevice : bondedDevices) {
// 這裏就打印下
Log.e("TAG", "-----------" + bondedDevice.getName());
}
}
// 點擊按鈕開始掃描附近藍牙設備
public void scan(View view) {
// 掃描藍牙必須是打開狀態,先判斷藍牙的狀態
if (bluetoothAdapter.isEnabled()) {
// 打開狀態 (6.0以上,掃描必須動態獲取地理位置權限)
if (Build.VERSION.SDK_INT >= 23) {
int check = checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION);
if (check == PackageManager.PERMISSION_GRANTED) {
startScan();
} else {
// 請求權限(執行完就會執行權限請求結果的方法onRequestPermissionsResult())
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
}
} else {
// 開始掃描
startScan();
}
} else {
// 關閉狀態
request(view);
}
}
private void startScan() {
// 以廣播的方式來發送藍牙設備
// 判斷藍牙是否正在掃描中
if (!bluetoothAdapter.isDiscovering()) {
// 開始掃描
bluetoothAdapter.startDiscovery();
}
// 停止掃描
//bluetoothAdapter.cancelDiscovery();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// 判斷結果(requestCode要與上面的相同,grantResults[0]是數組0座標位置的權限)
if (requestCode == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 開始掃描
startScan();
} else {
Toast.makeText(this, "由於android版本高於6.0必須獲取地理位置才能掃描藍牙", Toast.LENGTH_SHORT).show();
}
}
// 通過廣播接收者來接收藍牙設備
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// 藍牙設備被發現的監聽
if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
// 獲取到其它的藍牙設備
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 從藍牙設備中獲取具體的數據,獲取藍牙的名稱(如果沒有名稱就顯示匿名)
String name = device.getName() == null ? "匿名" : device.getName();
// 把藍牙名稱添加到集合
deviceNames.add(name);
adapter.notifyDataSetChanged();
// 把藍牙設備添加到集合
devices.add(device);
}
}
};
@Override
protected void onResume() {
super.onResume();
// 註冊廣播接受者
registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
}
@Override
protected void onPause() {
super.onPause();
// 註銷廣播接收者
unregisterReceiver(receiver);
}
// 點擊按鈕建立連接
public void startServer(View view) {
if (server == null) {
server = new MyServer();
// 開啓線程
server.start();
}
}
MyServer server;
// 手機連接的UUID(可以隨機獲取),設備連接非UUID由廠商決定
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// 點擊列表請求服務器 從藍牙設備集合中獲取藍牙設備
final BluetoothDevice device = devices.get(position);
// 需要耗時創建一個子線程
new Thread(){
@Override
public void run() {
super.run();
// 創建一個安全的連接
try {
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(uuid);
// 必須要調socket.connect()才能打開流
socket.connect();
// 獲取輸出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write("你好!藍牙服務器".getBytes());
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
class MyServer extends Thread {
@Override
public void run() {
super.run();
BluetoothServerSocket bluetoothServerSocket;
try {
// 使用網絡了所以要創建子線程
bluetoothServerSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(bluetoothAdapter.getName(), uuid);
// 等待客戶的連接
BluetoothSocket socket = bluetoothServerSocket.accept();
// 如果是連接狀態就一直創建流讀取數據(客戶端在ListView上顯示,點擊就請求服務器,接下來設置它的點擊事件)
while (socket.isConnected()) {
// 從socket裏面獲取輸入流讀取數據
InputStream inputStream = socket.getInputStream();
int len = 0;
byte[] buf = new byte[1024];
while ((len = inputStream.read(buf)) != -1) {
Log.e("TAG", "----------------" + new String(buf, 0, len, "utf-8"));
}
}
// 執行run方法後返回一個客戶端,服務端就可以關閉了(藍牙設備裏面必須1對1所以可以關閉服務端,而TCP是1對多的所要服務器不能關閉)
bluetoothServerSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
// 這裏等於null是爲了下次還可以再建立服務端
bluetoothServerSocket = null;
}
}
}