鸿蒙跨设备相机拍照应用开发指南 原创

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

鸿蒙跨设备相机拍照应用开发指南

一、项目概述

本文将基于HarmonyOS开发一个跨设备相机拍照应用,实现调用系统相机拍照、保存照片以及多设备间照片同步功能。借鉴《鸿蒙跨端U同步》中的技术原理,我们将实现类似游戏中多设备玩家状态同步的机制,使拍摄的照片能够在多个设备间实时共享。

二、技术架构

±--------------------+ ±--------------------+
用户界面层 <-----> 数据同步服务
±--------------------+ ±--------------------+

±---------v----------+ ±---------v----------+
相机服务模块 分布式数据管理
±--------------------+ ±--------------------+

±---------v-----------------------------v----------+
HarmonyOS系统服务 |

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

三、核心代码实现
相机服务封装

public class CameraService {
private static final String TAG = “CameraService”;
private static final int REQUEST_CODE_CAMERA = 1001;

private final AbilitySlice slice;
private PhotoCaptureCallback captureCallback;

public CameraService(AbilitySlice slice) {
    this.slice = slice;

// 启动相机拍照

public void takePhoto(PhotoCaptureCallback callback) {
    this.captureCallback = callback;
    
    Intent intent = new Intent();
    Operation operation = new Intent.OperationBuilder()
        .withAction("android.media.action.IMAGE_CAPTURE")
        .build();
    intent.setOperation(operation);
    
    slice.startAbilityForResult(intent, REQUEST_CODE_CAMERA);

// 处理拍照结果

public void handleActivityResult(int requestCode, Intent intent) {
    if (requestCode == REQUEST_CODE_CAMERA && captureCallback != null) {
        if (intent != null && intent.getData() != null) {
            captureCallback.onPhotoCaptured(intent.getData());

else {

            captureCallback.onCaptureFailed("拍照失败");

}

public interface PhotoCaptureCallback {

    void onPhotoCaptured(Uri photoUri);
    void onCaptureFailed(String error);

}

照片同步服务

public class PhotoSyncService {
private static final String TAG = “PhotoSyncService”;
private static final String SYNC_CHANNEL = “photo_sync”;
private static PhotoSyncService instance;

private final DistributedDataManager dataManager;
private final Map<String, PhotoSyncListener> listeners = new HashMap<>();

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

public static synchronized PhotoSyncService getInstance(Context context) {

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

return instance;

private void initDataListener() {

    dataManager.registerDataChangeListener(SYNC_CHANNEL, new DataChangeListener() {
        @Override
        public void onDataChanged(String deviceId, String key, String value) {
            try {
                JSONObject json = new JSONObject(value);
                String photoId = json.getString("photoId");
                String photoUri = json.getString("photoUri");
                String deviceName = json.getString("deviceName");
                
                if (!deviceId.equals(DistributedDeviceInfo.getLocalDeviceId())) {
                    PhotoSyncListener listener = listeners.get(photoId);
                    if (listener != null) {
                        listener.onPhotoSynced(photoId, photoUri, deviceName);

}

catch (JSONException e) {

                HiLog.error(TAG, "解析照片数据失败");

}

    });

// 同步照片到其他设备

public void syncPhoto(String photoId, String photoUri) {
    try {
        JSONObject json = new JSONObject();
        json.put("photoId", photoId);
        json.put("photoUri", photoUri);
        json.put("deviceName", DistributedDeviceInfo.getLocalDeviceName());
        json.put("timestamp", System.currentTimeMillis());
        
        dataManager.putString(SYNC_CHANNEL, json.toString());

catch (JSONException e) {

        HiLog.error(TAG, "序列化照片数据失败");

}

public void registerListener(String photoId, PhotoSyncListener listener) {
    listeners.put(photoId, listener);

public void unregisterListener(String photoId) {

    listeners.remove(photoId);

public interface PhotoSyncListener {

    void onPhotoSynced(String photoId, String photoUri, String fromDevice);

}

照片存储管理

public class PhotoStorage {
private static final String TAG = “PhotoStorage”;
private static final String PHOTO_DIR = “photos”;
private static PhotoStorage instance;

private final Context context;
private final File photoDirectory;

private PhotoStorage(Context context) {
    this.context = context;
    this.photoDirectory = new File(context.getExternalFilesDir(null), PHOTO_DIR);
    if (!photoDirectory.exists()) {
        photoDirectory.mkdirs();

}

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

return instance;

// 保存照片到本地

public String savePhoto(Uri photoUri) throws IOException {
    String photoId = UUID.randomUUID().toString();
    File destFile = new File(photoDirectory, photoId + ".jpg");
    
    try (InputStream in = context.getContentResolver().openInputStream(photoUri);
         OutputStream out = new FileOutputStream(destFile)) {
        byte[] buffer = new byte[1024];
        int len;
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);

}

    return photoId;

// 获取照片文件

public File getPhotoFile(String photoId) {
    return new File(photoDirectory, photoId + ".jpg");

// 获取所有照片ID

public List<String> getAllPhotoIds() {
    List<String> photoIds = new ArrayList<>();
    File[] files = photoDirectory.listFiles((dir, name) -> name.endsWith(".jpg"));
    
    if (files != null) {
        for (File file : files) {
            photoIds.add(file.getName().replace(".jpg", ""));

}

    return photoIds;

}

拍照界面实现

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

private CameraService cameraService;
private PhotoStorage photoStorage;
private PhotoSyncService syncService;

private Image photoPreview;
private Button takePhotoBtn;
private Button viewGalleryBtn;
private Text statusText;

@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    setUIContent(ResourceTable.Layout_camera_layout);
    
    // 初始化服务
    cameraService = new CameraService(this);
    photoStorage = PhotoStorage.getInstance(this);
    syncService = PhotoSyncService.getInstance(this);
    
    // 获取UI组件
    photoPreview = (Image) findComponentById(ResourceTable.Id_photo_preview);
    takePhotoBtn = (Button) findComponentById(ResourceTable.Id_take_photo_btn);
    viewGalleryBtn = (Button) findComponentById(ResourceTable.Id_view_gallery_btn);
    statusText = (Text) findComponentById(ResourceTable.Id_status_text);
    
    // 设置按钮事件
    takePhotoBtn.setClickedListener(component -> takePhoto());
    viewGalleryBtn.setClickedListener(component -> viewGallery());

private void takePhoto() {

    cameraService.takePhoto(new CameraService.PhotoCaptureCallback() {
        @Override
        public void onPhotoCaptured(Uri photoUri) {
            getUITaskDispatcher().asyncDispatch(() -> {
                try {
                    String photoId = photoStorage.savePhoto(photoUri);
                    File photoFile = photoStorage.getPhotoFile(photoId);
                    
                    // 显示预览
                    PixelMap pixelMap = ImageUtils.getPixelMapFromFile(photoFile);
                    photoPreview.setPixelMap(pixelMap);
                    
                    // 同步到其他设备
                    syncService.syncPhoto(photoId, photoFile.getAbsolutePath());
                    statusText.setText("照片已保存并同步");

catch (IOException e) {

                    statusText.setText("保存照片失败");

});

@Override

        public void onCaptureFailed(String error) {
            getUITaskDispatcher().asyncDispatch(() -> {
                statusText.setText(error);
            });

});

private void viewGallery() {

    Intent intent = new Intent();
    Operation operation = new Intent.OperationBuilder()
        .withDeviceId("")
        .withBundleName(getBundleName())
        .withAbilityName("GalleryAbility")
        .build();
    intent.setOperation(operation);
    startAbility(intent);

@Override

protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
    super.onAbilityResult(requestCode, resultCode, resultData);
    cameraService.handleActivityResult(requestCode, resultData);

}

照片画廊界面

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

private PhotoStorage photoStorage;
private ListContainer photoList;

@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    setUIContent(ResourceTable.Layout_gallery_layout);
    
    photoStorage = PhotoStorage.getInstance(this);
    photoList = (ListContainer) findComponentById(ResourceTable.Id_photo_list);
    
    refreshPhotoList();

private void refreshPhotoList() {

    List<String> photoIds = photoStorage.getAllPhotoIds();
    photoList.setItemProvider(new PhotoListAdapter(photoIds, this));

private static class PhotoListAdapter extends BaseItemProvider {

    private final List<String> photoIds;
    private final AbilitySlice slice;
    
    public PhotoListAdapter(List<String> photoIds, AbilitySlice slice) {
        this.photoIds = photoIds;
        this.slice = slice;

@Override

    public int getCount() {
        return photoIds.size();

@Override

    public Object getItem(int position) {
        return photoIds.get(position);

@Override

    public long getItemId(int position) {
        return position;

@Override

    public Component getComponent(int position, Component convertComponent, ComponentContainer parent) {
        DirectionalLayout itemLayout = (DirectionalLayout) LayoutScatter.getInstance(slice)
            .parse(ResourceTable.Layout_photo_item_layout, null, false);
        
        String photoId = photoIds.get(position);
        Image photoImage = (Image) itemLayout.findComponentById(ResourceTable.Id_photo_image);
        
        new Thread(() -> {
            File photoFile = PhotoStorage.getInstance(slice).getPhotoFile(photoId);
            PixelMap pixelMap = ImageUtils.getPixelMapFromFile(photoFile);
            getUITaskDispatcher().asyncDispatch(() -> {
                photoImage.setPixelMap(pixelMap);
            });
        }).start();
        
        itemLayout.setClickedListener(component -> {
            Intent intent = new Intent();
            Operation operation = new Intent.OperationBuilder()
                .withDeviceId("")
                .withBundleName(slice.getBundleName())
                .withAbilityName("PhotoViewAbility")
                .build();
            intent.setOperation(operation);
            intent.setParam("photoId", photoId);
            slice.startAbility(intent);
        });
        
        return itemLayout;

}

四、与游戏同步技术的结合点
状态同步机制:借鉴游戏中玩家状态同步方式,实现照片数据的跨设备同步

冲突解决策略:采用时间戳机制解决多设备同时修改的冲突

数据压缩传输:优化照片数据传输效率,类似游戏中资源同步

设备发现与管理:利用HarmonyOS分布式能力实现设备自动发现

五、项目扩展方向
照片编辑功能:添加滤镜、裁剪等编辑工具

智能分类:基于AI的照片自动分类

云存储集成:将照片备份到云端

共享相册:创建多人协作的共享相册

实时协作拍摄:多设备同时拍摄不同角度的照片

六、总结

本文实现的跨设备相机拍照应用具有以下特点:
完整的拍照、保存、浏览功能流程

基于HarmonyOS分布式能力的多设备同步

高效的照片存储和管理机制

借鉴游戏同步技术的可靠数据传输

良好的用户体验和界面设计

通过这个项目,开发者可以学习到如何将游戏中的同步技术应用于实际应用开发,充分利用HarmonyOS的分布式能力,构建真正意义上的跨设备协同应用。

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