file-type

Android蓝牙聊天应用开发:快速集成与代码示例

ZIP文件

下载需积分: 13 | 101KB | 更新于2025-09-04 | 169 浏览量 | 1 下载量 举报 收藏
download 立即下载
根据提供的文件信息,我们将探讨Android蓝牙聊天应用开发中涉及的知识点,包括Android蓝牙API的使用、源代码示例的导入方法、以及如何快速集成蓝牙功能到自己的Android应用程序中。 ### Android蓝牙API的使用 Android平台上实现蓝牙功能,开发者需要使用Android SDK中的蓝牙API。这些API主要集中在`android.bluetooth`包中,它们允许应用程序搜索蓝牙设备、配对、建立连接、数据传输等功能。 #### 蓝牙搜索与配对 在蓝牙聊天应用中,首先需要搜索附近的蓝牙设备。这可以通过调用`BluetoothAdapter`类的相关方法实现。例如,使用`startDiscovery()`方法可以开始搜索附近的蓝牙设备。搜索到的设备会通过`BluetoothDevice`对象返回。 配对是指将两个蓝牙设备建立信任关系,这样它们就可以建立连接。在某些设备上,配对可以通过蓝牙设置进行手动配对,或者在应用中通过编程方式发起配对请求。 #### 蓝牙连接与数据传输 建立连接前,需要通过`BluetoothSocket`类来创建一个socket连接。连接是双向的,意味着你既可以发送数据,也可以接收数据。建立连接后,可以使用`OutputStream`和`InputStream`来传输数据。 ### 源代码示例的导入方法 在给定的文件信息中提到了一个具体的源代码示例路径`app/src/main/java/group/project/btech/bluchat_extend`,这是典型的Android项目结构中的一个路径。在实际开发中,导入一个源代码示例的步骤通常包括以下几个步骤: 1. 下载或复制整个示例项目的源代码。 2. 在IDE(如Android Studio)中导入项目。 3. 根据需要清理项目中不必要的文件和代码。 4. 将源代码示例中的重要部分复制到新项目或现有项目中。 ### 快速集成蓝牙功能到应用程序中 要在Android应用中快速集成蓝牙功能,开发者可以采取以下步骤: 1. **声明权限**: 在AndroidManifest.xml中声明必要的权限,比如`BLUETOOTH`和`BLUETOOTH_ADMIN`用于设备发现和管理,以及`ACCESS_FINE_LOCATION`用于在Android 6.0及以上版本搜索设备。 2. **获取蓝牙适配器**: 通过`BluetoothAdapter`获取系统的蓝牙适配器实例,这是与蓝牙硬件交互的入口。 3. **实现蓝牙设备的搜索**: 通过适配器的`startDiscovery()`方法和`BluetoothDeviceDiscoveryListener`接口来发现蓝牙设备。 4. **建立蓝牙连接**: 通过`BluetoothAdapter`的`getRemoteDevice()`方法获取设备实例,然后尝试与远程设备通过`BluetoothSocket`建立连接。 5. **数据通信**: 在建立起的`BluetoothSocket`上进行输入输出流的读写,实现数据的传输。 ### MainActivity文件中的简单代码 `MainActivity`文件通常作为应用的主入口点,它在`OnCreate`方法中初始化UI和其他重要组件。在蓝牙聊天应用中,`MainActivity`可能包含查找设备、发起连接以及界面更新的代码。由于这些代码被描述为“简单且易于说明”,我们可以推测这些代码为初学者提供了一个基础的框架来理解蓝牙通信的流程。 ### 创建自己的蓝牙聊天应用 根据给定的文件信息,创建一个蓝牙聊天应用涉及以下步骤: 1. **理解源代码**: 首先理解提供的示例源代码是如何工作的,特别是关注于如何搜索设备、建立连接和数据传输。 2. **代码整合**: 将理解后的代码整合到自己的项目中,可能需要调整代码以适应自己的应用架构。 3. **界面和逻辑开发**: 设计用户界面(UI),并添加逻辑代码以实现用户与应用的交互。 4. **测试**: 在不同设备上测试应用以确保蓝牙连接的稳定性和数据传输的正确性。 ### 系统开源 提到的“系统开源”意味着源代码示例的获取和使用应该是免费的,开发者可以查看源代码的具体实现,并根据自身的需要自由修改和扩展。这有助于快速学习和应用开发,同时也促进了社区之间的技术交流与合作。 ### 总结 通过以上分析,可以看出创建一个基于Android平台的蓝牙聊天应用需要理解蓝牙API的使用、学会如何导入和使用源代码示例,并且将这些知识应用到实际的开发过程中。利用现有的开源示例,开发者可以更快地构建出功能完整的应用程序,并在此基础上进行创新和扩展。

相关推荐

filetype

package com.example.heart_oxygen_monitoring_system; import android.Manifest; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import androidx.activity.EdgeToEdge; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.UUID; import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.http.Body; import retrofit2.http.Header; import retrofit2.http.POST; public class MainActivity extends AppCompatActivity { // UI组件 private TextView tvConnectionStatus; private TextView tvHeartRate; private TextView tvSpO2; private TextView tvTemperature; private Button btnScan; private EditText etQuestion; private Button btnAskAI; private TextView tvAIResponse; // 蓝牙相关 private BluetoothHelper bluetoothHelper; private BluetoothAdapter bluetoothAdapter; private BluetoothSocket bluetoothSocket; private ConnectedThread connectedThread; private final ArrayList<BluetoothDevice> deviceList = new ArrayList<>(); // AI相关 private ApiService apiService; private int currentHeartRate = 0; private int currentSpO2 = 0; private float currentTemperature = 0.0f; //权限和请求码 private static final int REQUEST_ENABLE_BT = 1; private static final int REQUEST_BLUETOOTH_PERMISSIONS = 2; private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); private static final String TAG = "MainActivity"; private ActivityResultLauncher<Intent> bluetoothEnableLauncher; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); // 初始化结果监听器 bluetoothEnableLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == RESULT_OK) { // 用户启用了蓝牙 startDeviceDiscovery(); } else { Toast.makeText(this, "蓝牙未启用", Toast.LENGTH_SHORT).show(); } }); initViews(); initBluetooth(); setupButtonListeners(); initAIService(); } private void initViews() { tvConnectionStatus = findViewById(R.id.tvConnectionStatus); tvHeartRate = findViewById(R.id.tvHeartRate); tvSpO2 = findViewById(R.id.tvSpO2); tvTemperature = findViewById(R.id.tvTemperature); btnScan = findViewById(R.id.btnScan); etQuestion = findViewById(R.id.etQuestion); btnAskAI = findViewById(R.id.btnAskAI); tvAIResponse = findViewById(R.id.tvAIResponse); updateBluetoothStatus(false); resetDataDisplay(); } private void resetDataDisplay() { tvHeartRate.setText("--"); tvSpO2.setText("--"); tvTemperature.setText("--"); } private void initBluetooth() { bluetoothHelper = new BluetoothHelper(this); bluetoothAdapter = bluetoothHelper.getBluetoothAdapter(); if (!bluetoothHelper.isBluetoothSupported()) { Toast.makeText(this, "设备不支持蓝牙", Toast.LENGTH_SHORT).show(); return; } // 注册广播接收器 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(deviceReceiver, filter); } private void initAIService() { // 创建HTTP日志拦截器 HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); // 创建OkHttpClient OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .build(); // 创建Retrofit实例 Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://192.168.88.105:8880/") // 替换为你的RAGFlow服务器地址 .client(client) .addConverterFactory(GsonConverterFactory.create()) .build(); // 创建API服务 apiService = retrofit.create(ApiService.class); } private void setupButtonListeners() { btnScan.setOnClickListener(v -> { if (checkPermissions()) { if (!bluetoothHelper.isBluetoothEnabled()) { requestEnableBluetooth(); } else { startDeviceDiscovery(); } } }); btnAskAI.setOnClickListener(v -> { String question = etQuestion.getText().toString().trim(); if (!question.isEmpty()) { askAI(question); } else { Toast.makeText(this, "请输入问题", Toast.LENGTH_SHORT).show(); } }); } private void requestEnableBluetooth() { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); bluetoothEnableLauncher.launch(enableBtIntent); } private void startDeviceDiscovery() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { return; } deviceList.clear(); if (bluetoothAdapter.isDiscovering()) { bluetoothAdapter.cancelDiscovery(); } if (bluetoothAdapter.startDiscovery()) { Toast.makeText(this, "正在搜索STM32设备...", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "搜索启动失败", Toast.LENGTH_SHORT).show(); } } private final BroadcastReceiver deviceReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { return; } // 只添加名称包含"STM32"的设备 assert device != null; if (device.getName() != null && device.getName().contains("STM32")) { if (!deviceList.contains(device)) { deviceList.add(device); showDeviceSelectionDialog(); } } } } }; private void showDeviceSelectionDialog() { if (deviceList.isEmpty()) return; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("选择STM32设备"); ArrayList<String> deviceNames = new ArrayList<>(); for (BluetoothDevice device : deviceList) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { continue; } deviceNames.add(device.getName() + "\n" + device.getAddress()); } builder.setItems(deviceNames.toArray(new String[0]), (dialog, which) -> connectToDevice(deviceList.get(which))); builder.setNegativeButton("取消", null); builder.show(); } private void connectToDevice(BluetoothDevice device) { try { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { return; } bluetoothSocket = device.createRfcommSocketToServiceRecord(MY_UUID); new Thread(() -> { try { bluetoothSocket.connect(); runOnUiThread(() -> { updateBluetoothStatus(true); Toast.makeText(MainActivity.this, "已连接到: " + device.getName(), Toast.LENGTH_SHORT).show(); }); // 启动数据接收线程 connectedThread = new ConnectedThread(bluetoothSocket); connectedThread.start(); } catch (IOException e) { runOnUiThread(() -> { updateBluetoothStatus(false); Toast.makeText(MainActivity.this, "连接失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); }); } }).start(); } catch (IOException e) { Toast.makeText(this, "创建连接失败", Toast.LENGTH_SHORT).show(); } } private class ConnectedThread extends Thread { private final InputStream mmInStream; private final byte[] mmBuffer = new byte[1024]; public ConnectedThread(BluetoothSocket socket) { InputStream tmpIn = null; try { tmpIn = socket.getInputStream(); } catch (IOException e) { Log.e(TAG, "获取输入流失败", e); } mmInStream = tmpIn; } public void run() { StringBuilder receivedData = new StringBuilder(); while (!Thread.interrupted()) { try { int bytes = mmInStream.read(mmBuffer); String chunk = new String(mmBuffer, 0, bytes); receivedData.append(chunk); // 检查是否收到完整数据包 if (chunk.contains("\n")) { final String completeData = receivedData.toString().trim(); receivedData.setLength(0); new Handler(Looper.getMainLooper()).post(() -> processSTM32Data(completeData)); } } catch (IOException e) { Log.e(TAG, "连接断开", e); runOnUiThread(() -> { updateBluetoothStatus(false); Toast.makeText(MainActivity.this, "与设备断开连接", Toast.LENGTH_SHORT).show(); }); break; } } } } private void processSTM32Data(String rawData) { // 示例数据格式: "HR:75,SpO2:98,Temp:36.5" try { String[] pairs = rawData.split(","); for (String pair : pairs) { String[] keyValue = pair.split(":"); if (keyValue.length == 2) { String key = keyValue[0].trim(); String value = keyValue[1].trim(); switch (key) { case "HR": updateHeartRate(value); break; case "SpO2": updateOxygenLevel(value); break; case "Temp": updateTemperature(value); break; } } } } catch (Exception e) { Log.e(TAG, "数据解析错误: " + rawData, e); } } private void updateHeartRate(String value) { tvHeartRate.setText(value); try { currentHeartRate = Integer.parseInt(value); tvHeartRate.setTextColor(currentHeartRate < 60 || currentHeartRate > 100 ? Color.RED : ContextCompat.getColor(this, R.color.primary)); } catch (NumberFormatException e) { tvHeartRate.setTextColor(ContextCompat.getColor(this, R.color.primary)); } } private void updateOxygenLevel(String value) { tvSpO2.setText(value); try { currentSpO2 = Integer.parseInt(value); tvSpO2.setTextColor(currentSpO2 < 90 ? Color.RED : ContextCompat.getColor(this, R.color.primary)); } catch (NumberFormatException e) { tvSpO2.setTextColor(ContextCompat.getColor(this, R.color.primary)); } } private void updateTemperature(String value) { tvTemperature.setText(value); try { currentTemperature = Float.parseFloat(value); } catch (NumberFormatException e) { // 忽略解析错误 } } private void updateBluetoothStatus(boolean isConnected) { if (isConnected) { tvConnectionStatus.setText("蓝牙状态: 已连接"); tvConnectionStatus.setTextColor(ContextCompat.getColor(this, R.color.green)); btnScan.setVisibility(View.GONE); } else { tvConnectionStatus.setText("蓝牙状态: 未连接"); tvConnectionStatus.setTextColor(ContextCompat.getColor(this, R.color.red)); btnScan.setVisibility(View.VISIBLE); resetDataDisplay(); } } private void askAI(String question) { // 显示加载中 tvAIResponse.setText("思考中..."); // 构建请求 ChatRequest.Message userMessage = new ChatRequest.Message("user", question); List<ChatRequest.Message> messages = new ArrayList<>(); messages.add(userMessage); ChatRequest request = new ChatRequest(); request.setModel("deepseek-r1:1.5b"); // 与你RAGFlow中配置的模型一致 request.setMessages(messages); request.setStream(false); // 异步调用 Call<ApiResponse> call = apiService.sendMessage("Bearer your_api_key_if_any", request); call.enqueue(new Callback<ApiResponse>() { @SuppressLint("SetTextI18n") @Override public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) { if (response.isSuccessful() && response.body() != null) { // 提取AI回复内容 String aiResponse = response.body().getChoices().get(0).getMessage().getContent(); tvAIResponse.setText(aiResponse); } else { tvAIResponse.setText("抱歉,请求失败: " + response.message()); } } @SuppressLint("SetTextI18n") @Override public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) { tvAIResponse.setText("网络错误: " + t.getMessage()); } }); } private void generateHealthAdvice() { @SuppressLint("DefaultLocale") String healthQuery = String.format( "我的心率是%d bpm,血氧是%d%%,体温是%.1f°C。请分析我的健康状况并提供简要建议。", currentHeartRate, currentSpO2, currentTemperature ); askAI(healthQuery); } private boolean checkPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED || checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{ Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.ACCESS_FINE_LOCATION }, REQUEST_BLUETOOTH_PERMISSIONS); return false; } } else { if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{ Manifest.permission.ACCESS_FINE_LOCATION }, REQUEST_BLUETOOTH_PERMISSIONS); return false; } } return true; } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_BLUETOOTH_PERMISSIONS) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { startDeviceDiscovery(); } 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 == REQUEST_ENABLE_BT) { if (resultCode == RESULT_OK) { startDeviceDiscovery(); } else { Toast.makeText(this, "蓝牙未启用", Toast.LENGTH_SHORT).show(); } } } @SuppressLint("MissingPermission") @Override protected void onDestroy() { super.onDestroy(); // 取消设备发现 if (bluetoothAdapter != null && bluetoothAdapter.isDiscovering()) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED) { bluetoothAdapter.cancelDiscovery(); } } // 注销广播接收器 try { unregisterReceiver(deviceReceiver); } catch (IllegalArgumentException e) { Log.e(TAG, "接收器未注册"); } // 关闭连接 if (connectedThread != null) { connectedThread.interrupt(); } if (bluetoothSocket != null) { try { bluetoothSocket.close(); } catch (IOException e) { Log.e(TAG, "关闭socket失败", e); } } } // API请求和响应数据模型 public static class ChatRequest { private String model; private List<Message> messages; private boolean stream = false; public String getModel() { return model; } public void setModel(String model) { this.model = model; } public List<Message> getMessages() { return messages; } public void setMessages(List<Message> messages) { this.messages = messages; } public boolean isStream() { return stream; } public void setStream(boolean stream) { this.stream = stream; } public static class Message { private String role; private String content; public Message(String role, String content) { this.role = role; this.content = content; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } } public static class ApiResponse { private String id; private List<Choice> choices; public String getId() { return id; } public void setId(String id) { this.id = id; } public List<Choice> getChoices() { return choices; } public void setChoices(List<Choice> choices) { this.choices = choices; } public static class Choice { private Message message; public Message getMessage() { return message; } public void setMessage(Message message) { this.message = message; } public static class Message { private String role; private String content; public String getRole() { return role; } public void setRole(String role) { this.role = role; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } } } // API服务接口 public interface ApiService { @POST("/api/v1/chat/completions") // 根据RAGFlow实际API端点调整 Call<ApiResponse> sendMessage( @Header("Authorization") String auth, @Body ChatRequest request ); } } 怎么修改

绘画窝
  • 粉丝: 34
上传资源 快速赚钱