You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android端Pydroid运行EXIF修改脚本遇PermissionError求助

解决方案:Android上批量更新WhatsApp图片EXIF数据

一、Pydroid环境下解决权限问题

1. 正确的权限申请方式

Pydroid自带专属的权限模块,无需使用Kivy的android包,替换成以下代码申请权限:

from pydroid.permissions import request_permissions, Permission

# 申请读写外部存储权限
request_permissions([Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE])

2. 适配Android 10+存储限制

  • 手动开启全文件访问权限:前往系统设置 → 应用 → Pydroid → 权限 → 开启「所有文件访问权限」,这是最简单的适配方式。
  • 若开启后仍报错,说明Scoped Storage限制了直接路径写入,可临时将图片复制到Pydroid的私有缓存目录修改,再移回原路径。

3. 脚本优化

  • piexif仅支持JPG/JPEG格式的EXIF写入,PNG/GIF格式不支持,建议移除脚本中的对应判断:
    if fname.lower().endswith(('.jpg', '.jpeg')):
    
  • 添加异常捕获,避免单文件处理失败导致脚本终止:
    try:
        exif_dict = piexif.load(img_path)
        # 后续EXIF修改逻辑
    except Exception as e:
        print(f"处理{img_path}失败: {str(e)}")
        continue
    

二、Java方案(适配全Android版本)

如果Python方案仍受限于权限,可使用Java实现,直接适配Android存储机制:

1. 配置权限(AndroidManifest.xml)

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" />

2. 核心更新代码

使用Android原生ExifInterface类批量修改EXIF:

import android.media.ExifInterface;
import android.os.Build;
import android.os.Environment;
import android.provider.Settings;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ExifUpdateActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 先申请权限
        requestPermissionsIfNeeded();
    }

    private void requestPermissionsIfNeeded() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (!Environment.isExternalStorageManager()) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
                startActivity(intent);
            } else {
                startUpdateExif();
            }
        } else {
            if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
            } else {
                startUpdateExif();
            }
        }
    }

    private void startUpdateExif() {
        String dirPath = "/storage/emulated/0/Android/media/com.whatsapp/WhatsApp/Media/WhatsApp Images";
        File rootDir = new File(dirPath);
        if (!rootDir.exists()) return;

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
        int updateCount = 1;

        scanDirectory(rootDir, dateFormat, updateCount);
    }

    private void scanDirectory(File dir, SimpleDateFormat dateFormat, int count) {
        File[] files = dir.listFiles();
        if (files == null) return;

        for (File file : files) {
            if (file.isDirectory()) {
                scanDirectory(file, dateFormat, count);
                continue;
            }

            String fileName = file.getName().toLowerCase();
            if (!fileName.endsWith(".jpg") && !fileName.endsWith(".jpeg")) continue;

            try {
                ExifInterface exif = new ExifInterface(file.getAbsolutePath());
                String originalDate = exif.getAttribute(ExifInterface.TAG_DATETIME_ORIGINAL);
                
                if (originalDate == null || originalDate.isEmpty()) {
                    long fileModifyTime = file.lastModified();
                    String newDateStr = dateFormat.format(new Date(fileModifyTime));
                    
                    exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL, newDateStr);
                    exif.saveAttributes();
                    
                    System.out.println("[" + count + "] 已更新: " + file.getAbsolutePath() + " → " + newDateStr);
                    count++;
                }
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("处理失败: " + file.getAbsolutePath());
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Filip Szczybura

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 06:06:08