• 作者:老汪软件技巧
  • 发表时间:2024-08-19 04:04
  • 浏览量:

最近项目 app (react native) 有个需求是复制一张本地二维码图片供用户长按下载,使用的 lib 是 react-native-fs,这个需求看似简单,实际上有不少的坑要踩,比如文件的路径,复制成功后无法查看到文件等,以下是具体的解决案例

Android

首先将图片放在 android/app/src/main/assets 目录下,记得重新 build 下,这个可不是添加即用的。调用 existsAssets 判断文件资源是否存在,如果存在,就调用 copyFileAssets 去保存图片

import RNFS from 'react-native-fs';
const androidSavePicture = async () => {
	// 无需前缀 / ,如果父目录是 assets ,直接文件名即可,否则需要写文件夹名称,如 common/origin.png
	const filepath = 'origin.png';
	// 存储在 Pictures 目录下,替换成你需要的名称
	const destPath = `${RNFS.PicturesDirectoryPath}/target.png`;
	const isExist = await RNFS.existsAssets(filepath);
	if (!isExist) {
		return;
	}
	RNFS.copyFileAssets(filepath, destPath)
		.then(() => {
			console.log('复制成功');
		})
		.catch((error) => {
			console.log('复制失败', error);
		});
};

实际测试下来,文件能下载成功,但是,去系统自带的图库却没能看到,要知道,大多数用户可不会打开文件 app,再定位到 Pictures 文件夹去查看的。其实,没法查看到图片的原因是 Android 的媒体扫描器(MediaScanner)没有立即检测到新添加的文件,像我用三星进行测试,重启手机会触发扫描,就能在图库中看到了,因此,解决方法是我们手动触发扫描,这需要写桥接文件,以下仅给出核心代码

    @ReactMethod
    public void scanFile(@NonNull String filePath) {
        Log.d("scanFile", "filePath: " + filePath);
        File file = new File(filePath);
        if (!file.exists()) {
            Toast.makeText(context, "文件不存在: " + filePath, Toast.LENGTH_LONG).show();
            return;
        }
        MediaScannerConnection.scanFile(context, new String[]{filePath}, null, (path, uri) -> {
            Log.d("scanFile", "path: " + path);
            Log.d("scanFile", "uri: " + uri.getPath());
        });
    }

在 copyFileAssets 的 then 回调里调用即可

NativeModules.RNMultifunctional.scanFile(destPath);

iOS

首先在 xcode 将图片拖动到 Resources 文件夹下,会跳出弹窗,根据情况会自动判断是创建引用(如果是项目已有的会创建引用)还是直接拷贝图片,project.pbxproj 会出现一些代码的更改,与 android 相同,都需要重新 build 下才可用

代码同样很简单,首先判断文件是否存在,存在就调用 copyFile api 保存即可

const iOSSavePicture = async () => {
	const filepath = RNFS.MainBundlePath + '/origin.png';
	const isExist = await RNFS.exists(filepath);
	if (!isExist) {
		return;
	}
	// 需要前缀 /
	const destPath = RNFS.DocumentDirectoryPath + '/target.png';
	RNFS.copyFile(filepath, destPath).then(() => {
		console.log('复制成功');
	}).catch(error => {
		console.log('复制失败', error);
	});
}

实际测试,发现走了 then 流程,图片成功拷贝,但在 iOS 自带的文件 app 中却无法查看到图片,具体原因跟 iOS 的一些权限配置有关,具体指 UIFileSharingEnabledandLSSupportsOpeningDocumentsInPlace,详情可以查看 /questions/5…

因此在 xcode 中配置,定位到 target、选中 info 的 Custom iOS Target Properties,添加上述两个 key,会分别显示成 Application supports iTunes file sharing 和 Supports opening documents in place,然后把 value 的值都改成 YES 即可

通过上述操作,保存成功后可以在 “我的 iPhone” 中看到一个与开发应用同名的文件夹,里面可以看到保存后的图片,功能成功实现

下载功能

比起复制本地文件,更常见的需求可能是下载网络图片到手机上,这个就比较简单了,用到的 api 是 downloadFile,最重要的参数有两个,fromUrl 和 toFile,fromUrl 很好理解,即图片链接,toFile 则可以等同于上面代码中的 destPath,以下是具体代码

const downloadFile = () => {
	const isAndroid = Platform.OS === 'android';
	const toFile = isAndroid ? `${RNFS.PicturesDirectoryPath}/target.png` : RNFS.DocumentDirectoryPath + '/target.png';
	RNFS.downloadFile({
		fromUrl: 'https://www.example.com/example.png',
		toFile,
	}).promise.then(downloadResult => {
		console.log('download result: ', downloadResult);
		if (isAndroid) {
			NativeModules.RNMultifunctional.scanFile(toFile);
		}
	});
}


上一条查看详情 +鸿蒙学习-Swiper、结构样式重用、Grid
下一条 查看详情 +没有了