跨设备手电筒工具:基于HarmonyOS的闪光灯控制与多设备同步系统 原创

进修的泡芙
发布于 2025-6-18 21:40
浏览
0收藏

跨设备手电筒工具:基于HarmonyOS的闪光灯控制与多设备同步系统

一、项目概述

本文实现一个基于HarmonyOS的手电筒工具,该工具能够控制设备摄像头闪光灯的开关,并借鉴《鸿蒙跨端U同步》中的状态同步机制,实现闪光灯状态在多设备间的实时同步。系统包含闪光灯控制、亮度调节、SOS求救信号以及跨设备状态同步等核心功能。

二、架构设计

±--------------------+ ±--------------------+
手电筒控制界面 <-----> 状态同步服务
(FlashlightSlice) (FlashSyncService)
±---------±---------+ ±---------±---------+

±---------v----------+ ±---------v----------+
闪光灯控制模块 分布式数据管理
(FlashlightManager) (DistributedData)
±---------±---------+ ±---------±---------+

±---------v-----------------------------v----------+
HarmonyOS基础服务 |

±--------------------------------------------------+

三、核心代码实现
闪光灯控制模块实现

public class FlashlightManager {
private static final String TAG = “FlashlightManager”;
private static FlashlightManager instance;

private CameraManager cameraManager;
private String cameraId;
private boolean isFlashlightOn = false;
private int currentBrightness = 100; // 默认亮度100%

private FlashlightManager(Context context) {
    cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
    try {
        // 获取第一个支持闪光灯的相机ID
        for (String id : cameraManager.getCameraIdList()) {
            CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id);
            Boolean hasFlash = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
            if (hasFlash != null && hasFlash) {
                cameraId = id;
                break;

}

catch (CameraAccessException e) {

        HiLog.error(TAG, "Failed to access camera: " + e.getMessage());

}

public static synchronized FlashlightManager getInstance(Context context) {
    if (instance == null) {
        instance = new FlashlightManager(context);

return instance;

// 打开闪光灯

public void turnOn() {
    if (cameraId == null) return;
    
    try {
        cameraManager.setTorchMode(cameraId, true);
        isFlashlightOn = true;

catch (CameraAccessException e) {

        HiLog.error(TAG, "Failed to turn on flashlight: " + e.getMessage());

}

// 关闭闪光灯
public void turnOff() {
    if (cameraId == null) return;
    
    try {
        cameraManager.setTorchMode(cameraId, false);
        isFlashlightOn = false;

catch (CameraAccessException e) {

        HiLog.error(TAG, "Failed to turn off flashlight: " + e.getMessage());

}

// 切换闪光灯状态
public void toggle() {
    if (isFlashlightOn) {
        turnOff();

else {

        turnOn();

}

// 设置闪光灯亮度(0-100)
public void setBrightness(int percent) {
    if (cameraId == null) return;
    
    currentBrightness = Math.max(0, Math.min(percent, 100));
    if (isFlashlightOn) {
        // 通过重新打开闪光灯应用亮度设置
        turnOff();
        turnOn();

}

// 发送SOS信号
public void sendSOS() {
    new Thread(() -> {
        String pattern = "···---···"; // SOS的莫尔斯电码
        for (int i = 0; i < pattern.length(); i++) {
            char c = pattern.charAt(i);
            if (c == '·') {
                // 短闪(200ms)
                turnOn();
                SystemClock.sleep(200);
                turnOff();

else if (c == ‘-’) {

                // 长闪(500ms)
                turnOn();
                SystemClock.sleep(500);
                turnOff();

// 字符间间隔(200ms)

            SystemClock.sleep(200);

}).start();

// 检查闪光灯是否可用

public boolean isFlashlightAvailable() {
    return cameraId != null;

// 检查闪光灯当前状态

public boolean isFlashlightOn() {
    return isFlashlightOn;

// 获取当前亮度

public int getCurrentBrightness() {
    return currentBrightness;

}

状态同步服务实现

public class FlashSyncService {
private static final String TAG = “FlashSyncService”;
private static final String SYNC_CHANNEL = “flashlight_sync”;
private static FlashSyncService instance;

private DistributedDataManager dataManager;
private FlashlightStateListener stateListener;

private FlashSyncService(Context context) {
    this.dataManager = DistributedDataManagerFactory.getInstance()
        .createDistributedDataManager(context);
    initDataListener();

public static synchronized FlashSyncService getInstance(Context context) {

    if (instance == null) {
        instance = new FlashSyncService(context);

return instance;

private void initDataListener() {

    dataManager.registerDataChangeListener(SYNC_CHANNEL, new DataChangeListener() {
        @Override
        public void onDataChanged(String deviceId, String key, String value) {
            try {
                JSONObject flashJson = new JSONObject(value);
                boolean isOn = flashJson.getBoolean("isOn");
                int brightness = flashJson.getInt("brightness");
                long timestamp = flashJson.getLong("timestamp");
                String deviceName = flashJson.getString("deviceName");
                
                // 忽略本地设备发送的更新
                if (deviceId.equals(DistributedDeviceInfo.getLocalDeviceId())) {
                    return;

if (stateListener != null) {

                    stateListener.onFlashlightStateChanged(isOn, brightness, deviceName);

} catch (JSONException e) {

                HiLog.error(TAG, "Failed to parse flashlight data");

}

    });

// 同步闪光灯状态

public void syncFlashlightState(boolean isOn, int brightness) {
    JSONObject flashJson = new JSONObject();
    try {
        flashJson.put("isOn", isOn);
        flashJson.put("brightness", brightness);
        flashJson.put("timestamp", System.currentTimeMillis());
        flashJson.put("deviceName", DistributedDeviceInfo.getLocalDeviceName());
        flashJson.put("version", getNextVersion());
        
        DistributedOptions options = new DistributedOptions();
        options.setPriority(DistributedOptions.Priority.HIGH);
        
        dataManager.putString(SYNC_CHANNEL, 
            flashJson.toString(), 
            DistributedDataManager.PUT_MODE_RELIABLE, 
            options);

catch (JSONException e) {

        HiLog.error(TAG, "Failed to serialize flashlight data");

}

// 注册状态监听器
public void registerStateListener(FlashlightStateListener listener) {
    this.stateListener = listener;

// 取消注册监听器

public void unregisterStateListener() {
    this.stateListener = null;

public interface FlashlightStateListener {

    void onFlashlightStateChanged(boolean isOn, int brightness, String fromDevice);

private int versionCounter = 0;

private synchronized int getNextVersion() {
    return ++versionCounter;

}

手电筒控制界面实现

public class FlashlightSlice extends AbilitySlice {
private static final String TAG = “FlashlightSlice”;

private FlashlightManager flashlightManager;
private FlashSyncService syncService;

private Button toggleBtn;
private Text statusText;
private Slider brightnessSlider;
private Button sosBtn;
private Text syncStatusText;

@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    setUIContent(ResourceTable.Layout_flashlight_layout);
    
    // 初始化服务
    flashlightManager = FlashlightManager.getInstance(this);
    syncService = FlashSyncService.getInstance(this);
    
    // 获取UI组件
    toggleBtn = (Button) findComponentById(ResourceTable.Id_toggle_btn);
    statusText = (Text) findComponentById(ResourceTable.Id_status_text);
    brightnessSlider = (Slider) findComponentById(ResourceTable.Id_brightness_slider);
    sosBtn = (Button) findComponentById(ResourceTable.Id_sos_btn);
    syncStatusText = (Text) findComponentById(ResourceTable.Id_sync_status);
    
    // 检查闪光灯是否可用
    if (!flashlightManager.isFlashlightAvailable()) {
        statusText.setText("闪光灯不可用");
        toggleBtn.setEnabled(false);
        brightnessSlider.setEnabled(false);
        sosBtn.setEnabled(false);
        return;

// 设置初始状态

    updateUI();
    
    // 设置按钮事件
    toggleBtn.setClickedListener(component -> {
        flashlightManager.toggle();
        updateUI();
        syncService.syncFlashlightState(
            flashlightManager.isFlashlightOn(),
            flashlightManager.getCurrentBrightness()
        );
    });
    
    brightnessSlider.setValueChangedListener((slider, value, fromUser) -> {
        if (fromUser) {
            flashlightManager.setBrightness(value);
            if (flashlightManager.isFlashlightOn()) {
                syncService.syncFlashlightState(true, value);

updateUI();

});

    sosBtn.setClickedListener(component -> {
        flashlightManager.sendSOS();
        syncStatusText.setText("已发送SOS信号");
    });
    
    // 注册同步监听器
    syncService.registerStateListener(new FlashSyncService.FlashlightStateListener() {
        @Override
        public void onFlashlightStateChanged(boolean isOn, int brightness, String fromDevice) {
            getUITaskDispatcher().asyncDispatch(() -> {
                if (isOn != flashlightManager.isFlashlightOn()) {
                    flashlightManager.toggle();

if (brightness != flashlightManager.getCurrentBrightness()) {

                    flashlightManager.setBrightness(brightness);

updateUI();

                syncStatusText.setText("已与" + fromDevice + "同步状态");
            });

});

private void updateUI() {

    boolean isOn = flashlightManager.isFlashlightOn();
    int brightness = flashlightManager.getCurrentBrightness();
    
    toggleBtn.setText(isOn ? "关闭闪光灯" : "打开闪光灯");
    statusText.setText(isOn ? 
        "闪光灯已开启 (" + brightness + "%)" : 
        "闪光灯已关闭");
    brightnessSlider.setProgressValue(brightness);
    brightnessSlider.setEnabled(isOn);

@Override

protected void onStop() {
    super.onStop();
    // 关闭闪光灯
    if (flashlightManager.isFlashlightOn()) {
        flashlightManager.turnOff();

// 取消注册监听器

    syncService.unregisterStateListener();

}

XML布局文件

<DirectionalLayout
xmlns:ohos=“http://schemas.huawei.com/res/ohos
ohos:width=“match_parent”
ohos:height=“match_parent”
ohos:orientation=“vertical”
ohos:padding=“24vp”
ohos:background_element=“#FF000000”>

<Text
    ohos:id="$+id:status_text"
    ohos:width="match_parent"
    ohos:height="wrap_content"
    ohos:text="闪光灯状态"
    ohos:text_size="24fp"
    ohos:text_color="#FFFFFFFF"
    ohos:margin_bottom="24vp"
    ohos:text_alignment="center"/>
    
<Button
    ohos:id="$+id:toggle_btn"
    ohos:width="match_parent"
    ohos:height="80vp"
    ohos:text="打开闪光灯"
    ohos:text_size="20fp"
    ohos:margin_bottom="24vp"/>
    
<Slider
    ohos:id="$+id:brightness_slider"
    ohos:width="match_parent"
    ohos:height="wrap_content"
    ohos:min_value="10"
    ohos:max_value="100"
    ohos:progress_value="100"
    ohos:margin_bottom="24vp"
    ohos:enabled="false"/>
    
<Text
    ohos:width="match_parent"
    ohos:height="wrap_content"
    ohos:text="亮度调节"
    ohos:text_size="16fp"
    ohos:text_color="#FFFFFFFF"
    ohos:margin_bottom="8vp"
    ohos:text_alignment="center"/>
    
<Button
    ohos:id="$+id:sos_btn"
    ohos:width="match_parent"
    ohos:height="60vp"
    ohos:text="SOS求救信号"
    ohos:text_color="#FFFF0000"
    ohos:margin_bottom="24vp"/>
    
<Text
    ohos:id="$+id:sync_status"
    ohos:width="match_parent"
    ohos:height="wrap_content"
    ohos:text="同步状态: 等待同步"
    ohos:text_size="14fp"
    ohos:text_color="#FFAAAAAA"
    ohos:text_alignment="center"/>

</DirectionalLayout>

Ability配置 (config.json)

“abilities”: [

“name”: “FlashlightAbility”,

  "type": "page",
  "label": "Flashlight",
  "icon": "$media:flashlight_icon",
  "launchType": "standard",
  "backgroundModes": ["dataSync"],
  "permissions": ["ohos.permission.CAMERA"]

],

“reqPermissions”: [
“name”: “ohos.permission.CAMERA”,

  "reason": "控制摄像头闪光灯",
  "usedScene": {
    "ability": ["FlashlightAbility"],
    "when": "always"

}

}

四、与《鸿蒙跨端U同步》的技术关联

本项目借鉴了游戏多设备同步的以下关键技术:
状态同步模型:类似游戏中玩家状态的实时同步,闪光灯状态通过JSON格式广播

设备标识:使用设备名称区分不同来源的状态更新

版本控制:引入版本号解决潜在的冲突问题

可靠传输:使用高优先级的数据传输确保同步成功率

即时响应:类似游戏中的实时响应,确保闪光灯状态同步的即时性

增强的同步逻辑(借鉴游戏同步机制):

// 增强的闪光灯状态同步方法
public void syncFlashlightState(boolean isOn, int brightness) {
JSONObject flashJson = new JSONObject();
try {
flashJson.put(“isOn”, isOn);
flashJson.put(“brightness”, brightness);
flashJson.put(“timestamp”, System.currentTimeMillis());
flashJson.put(“deviceName”, DistributedDeviceInfo.getLocalDeviceName());
flashJson.put(“version”, getNextVersion());

    // 增加校验码
    flashJson.put("checksum", calculateChecksum(isOn, brightness));
    
    // 设置传输选项
    DistributedOptions options = new DistributedOptions();
    options.setPriority(DistributedOptions.Priority.HIGH);
    options.setTimeToLive(30000); // 30秒有效期
    options.setRetryCount(3); // 重试3次
    
    // 使用可靠传输
    int result = dataManager.putString(SYNC_CHANNEL, 
        flashJson.toString(), 
        DistributedDataManager.PUT_MODE_RELIABLE, 
        options);
        
    if (result != 0) {
        HiLog.warn(TAG, "Flashlight sync failed with code: " + result);
        // 可以在这里实现重试逻辑

} catch (JSONException e) {

    HiLog.error(TAG, "Failed to serialize flashlight data");

}

// 校验闪光灯数据完整性
private boolean validateFlashlightData(JSONObject flashJson) {
try {
boolean isOn = flashJson.getBoolean(“isOn”);
int brightness = flashJson.getInt(“brightness”);
int checksum = flashJson.getInt(“checksum”);
return checksum == calculateChecksum(isOn, brightness);
catch (JSONException e) {

    return false;

}

// 简单的校验码计算
private int calculateChecksum(boolean isOn, int brightness) {
return (isOn ? 1 : 0) ^ brightness;

五、项目特色与创新点
完整的闪光灯控制:支持开关、亮度调节和SOS信号

跨设备同步:闪光灯状态可在多设备间实时同步

低功耗设计:优化闪光灯使用,减少电量消耗

紧急求救功能:内置SOS莫尔斯电码信号

直观的UI:简洁明了的用户界面

六、应用场景
日常照明:黑暗环境下的临时照明

户外活动:露营、徒步等户外场景

紧急求救:通过SOS信号发送求救信息

团队协作:多设备同步闪光灯作为信号指示

摄影辅助:作为临时补光工具

七、总结

本手电筒工具实现了以下功能:
控制设备摄像头闪光灯的开关

调节闪光灯亮度

发送SOS求救信号

多设备间闪光灯状态同步

简洁直观的用户界面

通过借鉴游戏中的状态同步技术,我们构建了一个可靠的跨设备闪光灯控制系统。未来可扩展功能包括:
闪光灯频率调节:支持不同频率的闪烁模式

颜色编码:通过RGB LED实现不同颜色的信号

定时关闭:设置闪光灯自动关闭时间

手势控制:通过手势切换闪光灯模式

这个项目展示了如何将游戏中的同步技术应用于实用工具开发,为用户提供强大的跨设备手电筒体验。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐