From f41a91f0165b0847d7d679ac74573ff156259fe9 Mon Sep 17 00:00:00 2001 From: tx <2622874537@qq.com> Date: Thu, 14 Nov 2024 17:48:38 +0800 Subject: [PATCH] 11 --- android/app/src/main/AndroidManifest.xml | 6 +- .../java/com/bikeapp_demo/MainApplication.kt | 5 +- .../com/bikeapp_demo/MediaScannerModule.java | 39 +++ package-lock.json | 248 +++++++++++++++++- package.json | 8 +- .../Image/{Bledis.png => 组 1139@2x.png} | Bin src/types/react-native-qrcode.d.ts | 20 ++ src/views/device/AddShare.tsx | 26 +- src/views/device/shareQrcode.tsx | 156 +++++++++++ 9 files changed, 492 insertions(+), 16 deletions(-) create mode 100644 android/app/src/main/java/com/bikeapp_demo/MediaScannerModule.java rename src/assets/Image/{Bledis.png => 组 1139@2x.png} (100%) create mode 100644 src/types/react-native-qrcode.d.ts create mode 100644 src/views/device/shareQrcode.tsx diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index bb4032f..c28f358 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,8 +8,10 @@ - - + + + + = PackageList(this).packages.apply { // Packages that cannot be autolinked yet can be added manually here, for example: - // add(MyReactNativePackage()) + add(MediaScannerPackage()) // 添加自定义包 } override fun getJSMainModuleName(): String = "index" @@ -40,4 +41,4 @@ class MainApplication : Application(), ReactApplication { load() } } -} +} \ No newline at end of file diff --git a/android/app/src/main/java/com/bikeapp_demo/MediaScannerModule.java b/android/app/src/main/java/com/bikeapp_demo/MediaScannerModule.java new file mode 100644 index 0000000..2494072 --- /dev/null +++ b/android/app/src/main/java/com/bikeapp_demo/MediaScannerModule.java @@ -0,0 +1,39 @@ +package com.yourapp; + +import android.content.Context; +import android.media.MediaScannerConnection; +import android.net.Uri; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.Callback; + +public class MediaScannerModule extends ReactContextBaseJavaModule { + + private final ReactApplicationContext reactContext; + + public MediaScannerModule(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + } + + @Override + public String getName() { + return "MediaScanner"; + } + + @ReactMethod + public void scanFile(String path, String mimeType, Callback callback) { + MediaScannerConnection.scanFile(reactContext, new String[]{path}, new String[]{mimeType}, + new MediaScannerConnection.OnScanCompletedListener() { + @Override + public void onScanCompleted(String path, Uri uri) { + if (uri != null) { + callback.invoke(null); + } else { + callback.invoke("Error scanning file"); + } + } + }); + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ed1d7f5..1485015 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,10 +15,13 @@ "@react-navigation/native": "^6.1.18", "@react-navigation/stack": "^6.3.8", "axios": "^1.7.7", + "qrcode": "^1.5.4", "react": "18.2.0", "react-native": "0.74.5", "react-native-amap3d": "^3.0.7", "react-native-camera": "^4.2.1", + "react-native-contacts": "^8.0.4", + "react-native-fs": "^2.20.0", "react-native-gesture-handler": "^2.20.2", "react-native-linear-gradient": "^2.8.3", "react-native-permissions": "^5.1.0", @@ -26,7 +29,10 @@ "react-native-reanimated": "^3.16.1", "react-native-safe-area-context": "^4.14.0", "react-native-screens": "^3.35.0", - "react-native-wheel-picker-android": "^2.0.6" + "react-native-share": "^11.0.4", + "react-native-view-shot": "^4.0.0", + "react-native-wheel-picker-android": "^2.0.6", + "rn-fetch-blob": "^0.12.0" }, "devDependencies": { "@babel/core": "^7.20.0", @@ -4044,6 +4050,19 @@ "version": "1.0.2", "license": "MIT" }, + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "funding": [ @@ -4585,6 +4604,14 @@ "node": ">= 8" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/csstype": { "version": "3.1.3", "devOptional": true, @@ -4780,6 +4807,11 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==" + }, "node_modules/dir-glob": { "version": "3.0.1", "dev": true, @@ -6351,6 +6383,18 @@ "dev": true, "license": "MIT" }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/http-errors": { "version": "2.0.0", "license": "MIT", @@ -8809,6 +8853,14 @@ "node": ">=8" } }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "dev": true, @@ -8934,6 +8986,83 @@ ], "license": "MIT" }, + "node_modules/qrcode": { + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/qrcode/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "node_modules/qrcode/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/query-string": { "version": "7.1.3", "license": "MIT", @@ -9094,6 +9223,33 @@ "prop-types": "^15.6.2" } }, + "node_modules/react-native-contacts": { + "version": "8.0.4", + "resolved": "https://registry.npmmirror.com/react-native-contacts/-/react-native-contacts-8.0.4.tgz", + "integrity": "sha512-uBwYlavWS1KjULKk7xLCZcLr6vQcmqLIeHzWY+MEKGtT28YjAlWG87N0bCaRKZSXvz/o/09tVqzU0ZOpkkJC1w==", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-fs": { + "version": "2.20.0", + "resolved": "https://registry.npmmirror.com/react-native-fs/-/react-native-fs-2.20.0.tgz", + "integrity": "sha512-VkTBzs7fIDUiy/XajOSNk0XazFE9l+QlMAce7lGuebZcag5CnjszB+u4BdqzwaQOdcYb5wsJIsqq4kxInIRpJQ==", + "dependencies": { + "base-64": "^0.1.0", + "utf8": "^3.0.0" + }, + "peerDependencies": { + "react-native": "*", + "react-native-windows": "*" + }, + "peerDependenciesMeta": { + "react-native-windows": { + "optional": true + } + } + }, "node_modules/react-native-gesture-handler": { "version": "2.20.2", "license": "MIT", @@ -9118,7 +9274,8 @@ }, "node_modules/react-native-permissions": { "version": "5.1.0", - "license": "MIT", + "resolved": "https://registry.npmmirror.com/react-native-permissions/-/react-native-permissions-5.1.0.tgz", + "integrity": "sha512-bRV8OHFAbLulElvbJ/BLtrYNV9WXStxknCuI5mTGJNIz6sl8sDUA0OhKpbtb0rqqDdJ2mbR1ZijhGkCDOaT0tA==", "peerDependencies": { "react": ">=18.1.0", "react-native": ">=0.70.0", @@ -9198,6 +9355,26 @@ "react-native": "*" } }, + "node_modules/react-native-share": { + "version": "11.0.4", + "resolved": "https://registry.npmmirror.com/react-native-share/-/react-native-share-11.0.4.tgz", + "integrity": "sha512-i91n1Pcdaxxr39uxR5KduXjqi5FSEXuEO6rmeHl8OPs5rqo4No36qJXUU6du4TZUI6tFSENdxnzZMh3OsMF+ug==", + "engines": { + "node": ">=16" + } + }, + "node_modules/react-native-view-shot": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/react-native-view-shot/-/react-native-view-shot-4.0.0.tgz", + "integrity": "sha512-e7wtfdm981DQVqkW+YE9mkemYarI0VZQ7PzRcHzQOmXlVrGKvNVD2MzRXOg+gK8msQIQ95QxATJKzG/QkQ9QHQ==", + "dependencies": { + "html2canvas": "^1.4.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-wheel-picker-android": { "version": "2.0.6", "resolved": "https://registry.npmmirror.com/react-native-wheel-picker-android/-/react-native-wheel-picker-android-2.0.6.tgz", @@ -9499,6 +9676,52 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rn-fetch-blob": { + "version": "0.12.0", + "resolved": "https://registry.npmmirror.com/rn-fetch-blob/-/rn-fetch-blob-0.12.0.tgz", + "integrity": "sha512-+QnR7AsJ14zqpVVUbzbtAjq0iI8c9tCg49tIoKO2ezjzRunN7YL6zFSFSWZm6d+mE/l9r+OeDM3jmb2tBb2WbA==", + "dependencies": { + "base-64": "0.1.0", + "glob": "7.0.6" + } + }, + "node_modules/rn-fetch-blob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rn-fetch-blob/node_modules/glob": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.0.6.tgz", + "integrity": "sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/rn-fetch-blob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "funding": [ @@ -10192,6 +10415,14 @@ "node": "*" } }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/text-table": { "version": "0.2.0", "dev": true, @@ -10513,6 +10744,11 @@ "react": ">=16.8" } }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" + }, "node_modules/util-deprecate": { "version": "1.0.2", "license": "MIT" @@ -10524,6 +10760,14 @@ "node": ">= 0.4.0" } }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "dev": true, diff --git a/package.json b/package.json index e1d7472..d6cf252 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,13 @@ "@react-navigation/native": "^6.1.18", "@react-navigation/stack": "^6.3.8", "axios": "^1.7.7", + "qrcode": "^1.5.4", "react": "18.2.0", "react-native": "0.74.5", "react-native-amap3d": "^3.0.7", "react-native-camera": "^4.2.1", + "react-native-contacts": "^8.0.4", + "react-native-fs": "^2.20.0", "react-native-gesture-handler": "^2.20.2", "react-native-linear-gradient": "^2.8.3", "react-native-permissions": "^5.1.0", @@ -28,7 +31,10 @@ "react-native-reanimated": "^3.16.1", "react-native-safe-area-context": "^4.14.0", "react-native-screens": "^3.35.0", - "react-native-wheel-picker-android": "^2.0.6" + "react-native-share": "^11.0.4", + "react-native-view-shot": "^4.0.0", + "react-native-wheel-picker-android": "^2.0.6", + "rn-fetch-blob": "^0.12.0" }, "devDependencies": { "@babel/core": "^7.20.0", diff --git a/src/assets/Image/Bledis.png b/src/assets/Image/组 1139@2x.png similarity index 100% rename from src/assets/Image/Bledis.png rename to src/assets/Image/组 1139@2x.png diff --git a/src/types/react-native-qrcode.d.ts b/src/types/react-native-qrcode.d.ts new file mode 100644 index 0000000..8a703bb --- /dev/null +++ b/src/types/react-native-qrcode.d.ts @@ -0,0 +1,20 @@ +declare module 'qrcode' { + interface QRCodeOptions { + version?: number; + errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H'; + width?: number; + margin?: number; + color?: { + dark?: string; + light?: string; + }; + } + + function toDataURL( + text: string, + options?: QRCodeOptions + ): Promise; + + export { toDataURL }; + export default { toDataURL }; +} \ No newline at end of file diff --git a/src/views/device/AddShare.tsx b/src/views/device/AddShare.tsx index 7f0fcec..0a856e6 100644 --- a/src/views/device/AddShare.tsx +++ b/src/views/device/AddShare.tsx @@ -1,9 +1,16 @@ import React, { useState } from 'react'; import { View, Text, StyleSheet, Image, TextInput, TouchableWithoutFeedback, Keyboard, TouchableOpacity, Modal } from 'react-native'; import { rpx } from '../../utils/rpx'; -import { useNavigation } from '@react-navigation/native'; +import { useNavigation, NavigationProp } from '@react-navigation/native'; + +type RootStackParamList = { + ShareQrcode: { + QrId: number; + }; +}; const AddShare = () => { - const navigation = useNavigation(); + const navigation = useNavigation>(); + const [phone, setPhone] = useState(''); const [name, setName] = useState(''); const [time, setTime] = useState(''); @@ -15,11 +22,12 @@ const AddShare = () => { setShowTimeModal(true); } const handleSubmit = () => { - navigation.navigate('ShareQrcode' as never); - } - const handlePhone = () => { - - } + navigation.navigate('ShareQrcode', { + QrId: 14 + }); + }; + + return ( @@ -30,12 +38,12 @@ const AddShare = () => { value={phone} onChangeText={setPhone} /> - + - + diff --git a/src/views/device/shareQrcode.tsx b/src/views/device/shareQrcode.tsx new file mode 100644 index 0000000..e076ce1 --- /dev/null +++ b/src/views/device/shareQrcode.tsx @@ -0,0 +1,156 @@ +import React from 'react'; +import { View, StyleSheet, Image, ImageBackground, TouchableOpacity, Text, Alert, Platform, NativeModules } from 'react-native'; +import { rpx } from '../../utils/rpx'; +import { RouteProp, useRoute } from '@react-navigation/native'; +import RNFS from 'react-native-fs'; +import { request, PERMISSIONS, RESULTS } from 'react-native-permissions'; + +const ShareQrcode = () => { + const route = useRoute>(); + const { QrId } = route.params; + + const qrCodeUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${rpx(400)}x${rpx(400)}&data=https://your-domain.com/share?id=${QrId}`; + console.log(qrCodeUrl); + + // const qrCodeUrl = `https://lxnapi.ccttiot.com/bike/img/static/upCrcuiBaoZrd9ZRZayj` + // https://lxnapi.ccttiot.com/bike/img/static/upCrcuiBaoZrd9ZRZayj + const saveToGallery = async () => { + try { + // 检查写入权限 + const writePermission = await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE); + const readPermission = await request(PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE); + + if (writePermission === RESULTS.GRANTED && readPermission === RESULTS.GRANTED) { + try { + const directoryPath = `${RNFS.DownloadDirectoryPath}`; + const fileName = `qrcode_${Date.now()}.jpg`; + let downloadDest = `${directoryPath}/${fileName}`; + + // 检查目录是否存在 + const exists = await RNFS.exists(directoryPath); + console.log('目录是否存在:', exists); + + if (!exists) { + console.log('尝试创建目录:', directoryPath); + try { + await RNFS.mkdir(directoryPath); + } catch (mkdirError) { + console.error('创建目录失败:', mkdirError); + // 如果创建目录失败,尝试直接使用根目录 + downloadDest = `${RNFS.ExternalStorageDirectoryPath}/${fileName}`; + } + } + + console.log('开始下载文件到:', downloadDest); + const options = { + fromUrl: qrCodeUrl, + toFile: downloadDest, + }; + + const response = await RNFS.downloadFile(options).promise; + console.log('下载响应:', response); + + if (response.statusCode === 200) { + const fileExists = await RNFS.exists(downloadDest); + if (fileExists) { + // 使用原生模块刷新媒体库 + NativeModules.MediaScanner.scanFile(downloadDest, 'image/jpeg', (err) => { + if (err) { + console.error('媒体扫描错误:', err); + Alert.alert('错误', '无法刷新媒体库'); + } else { + Alert.alert('成功', '二维码已保存到相册'); + } + }); + } else { + throw new Error('文件未能成功创建'); + } + } else { + Alert.alert('错误', '下载失败,请检查网络连接'); + } + } catch (err) { + console.error('文件操作详细错误:', JSON.stringify(err)); + Alert.alert('错误', '保存失败,无法访问存储空间'); + } + } else { + Alert.alert('权限不足', '请在设置中授予存储权限'); + } + } catch (error) { + console.error('整体错误:', error); + Alert.alert('错误', '保存失败,请重试'); + } + }; + return ( + + + + + + + + + + 保存至图片 + + + ); +} + + +// ... 其余代码保持不变 ... +const styles = StyleSheet.create({ + container: { + flex: 1, + alignItems: 'center', + backgroundColor: '#F3FCFF', + }, + btn: { + marginTop: rpx(36), + width: rpx(614), + height: rpx(92), + backgroundColor: '#3D3D3D', + borderRadius: rpx(16), + alignItems: 'center', + justifyContent: 'center', + }, + btnText: { + color: '#fff', + fontSize: rpx(40), + fontWeight: 'bold', + }, + tipImg: { + marginTop: rpx(26), + width: rpx(614), + height: rpx(368), + }, + qrCode:{ + width: rpx(438), + height: rpx(438), + }, + qrContainer: { + alignItems: 'center', + justifyContent: 'center', + // marginTop: rpx(-50), + }, + qrBack: { + marginTop: rpx(-20), + width: rpx(614), + height: rpx(614), + padding: rpx(86), + }, + backimg: { + width: rpx(688), + height: rpx(236), + } +}); + +export default ShareQrcode; \ No newline at end of file