diff --git a/android/app/build.gradle b/android/app/build.gradle
index 2f881f4..36f4606 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -147,17 +147,26 @@ android {
}
}
}
+ packagingOptions {
+ //当项目中出现多个同名的so文件会编译异常,过滤多余的so文件
+ pickFirst '**/libfbjni.so'
+ pickFirst '**/libc++_shared.so'
+ pickFirst '**/libjsc.so'
+ }
}
dependencies {
- implementation project(':@react-native-community_async-storage')
- implementation project(':react-native-music-control')
- implementation project(':react-native-vector-icons')
- implementation project(':react-native-gesture-handler')
- implementation project(':react-native-video')
+ implementation project(path: ':@react-native-community_toolbar-android')
+ implementation project(path: ':@react-native-community_async-storage')
+ implementation project(path: ':react-native-music-control')
+ implementation project(path: ':react-native-vector-icons')
+ implementation project(path: ':react-native-gesture-handler')
+ implementation project(path: ':react-native-screens')
+ implementation project(path: ':react-native-video')
implementation fileTree(dir: "libs", include: ["*.jar"])
- implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
+ implementation "androidx.activity:activity:1.3.0"
implementation "com.facebook.react:react-native:+" // From node_modules
+ implementation "org.webkit:android-jsc:+"
}
// Run this once to be able to run the application with BUCK
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 262c066..6aec55c 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,31 +1,35 @@
+ package="com.listen1.app">
-
-
-
-
-
-
-
-
+ android:requestLegacyExternalStorage="true"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:theme="@style/AppTheme"
+ android:usesCleartextTraffic="true">
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/java/com/listen1/app/MainApplication.java b/android/app/src/main/java/com/listen1/app/MainApplication.java
index 2a4c5e4..a8ae68b 100644
--- a/android/app/src/main/java/com/listen1/app/MainApplication.java
+++ b/android/app/src/main/java/com/listen1/app/MainApplication.java
@@ -29,12 +29,13 @@ public boolean getUseDeveloperSupport() {
@Override
protected List getPackages() {
return Arrays.asList(
- new MainReactPackage(),
- new AsyncStoragePackage(),
- new MusicControl(),
- new VectorIconsPackage(),
- new RNGestureHandlerPackage(),
- new ReactVideoPackage()
+ new MainReactPackage(),
+ new MainPackage(),
+ new AsyncStoragePackage(),
+ new MusicControl(),
+ new VectorIconsPackage(),
+ new RNGestureHandlerPackage(),
+ new ReactVideoPackage()
);
}
diff --git a/android/app/src/main/java/com/listen1/app/MainPackage.java b/android/app/src/main/java/com/listen1/app/MainPackage.java
new file mode 100644
index 0000000..ac77479
--- /dev/null
+++ b/android/app/src/main/java/com/listen1/app/MainPackage.java
@@ -0,0 +1,35 @@
+package com.listen1.app;
+
+import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.ViewManager;
+import com.listen1.app.utils.FileConfig;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * @Description: java类作用描述
+ * @Author: Void
+ * @CreateDate: 2023/1/11 15:31
+ * @UpdateDate: 2023/1/11 15:31
+ */
+public class MainPackage implements ReactPackage {
+ @Nonnull
+ @Override
+ public List createNativeModules(@Nonnull ReactApplicationContext context) {
+ List modules = new ArrayList<>();
+ modules.add(new FileConfig(context));
+ return modules;
+ }
+
+ @Nonnull
+ @Override
+ public List createViewManagers(@Nonnull ReactApplicationContext reactApplicationContext) {
+ return Collections.emptyList();
+ }
+}
diff --git a/android/app/src/main/java/com/listen1/app/OpenFileActivity.java b/android/app/src/main/java/com/listen1/app/OpenFileActivity.java
new file mode 100644
index 0000000..5540d9b
--- /dev/null
+++ b/android/app/src/main/java/com/listen1/app/OpenFileActivity.java
@@ -0,0 +1,148 @@
+package com.listen1.app;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+import androidx.annotation.Nullable;
+import com.listen1.app.utils.FileConfig;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public class OpenFileActivity extends PermissionActivity {
+ private final String[] readStoragePermissions = new String[]{
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ };
+ private int openFileRequestCode = -1;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ openFileRequestCode = getIntent().getIntExtra("OPEN_FILE_REQUEST_CODE", -1);
+ checkPermission();
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode != 1001) return;
+ if (data == null) {
+ backResult("", false);
+ return;
+ }
+ byte[] bytes = new byte[50];
+ StringBuilder builder = new StringBuilder();
+ Uri uri = data.getData();
+ new Thread() {
+ @Override
+ public void run() {
+ super.run();
+ FileInputStream fileInputStream = null;
+ ParcelFileDescriptor descriptor = null;
+ int endLength;
+ try {
+ descriptor = getContentResolver().openFileDescriptor(uri, "r");
+ fileInputStream = new FileInputStream(descriptor.getFileDescriptor());
+ while ((endLength = fileInputStream.read(bytes)) > 0) {
+ builder.append(new String(bytes, 0, endLength));
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ backResult("", false);
+ } finally {
+ try {
+ if (descriptor != null) descriptor.close();
+ if (fileInputStream != null) fileInputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ backResult(builder.toString(), false);
+ }
+ }
+ }.start();
+ }
+
+ @Override
+ protected String[] getPermissionArray() {
+ return readStoragePermissions;
+ }
+
+ @Override
+ protected String getDialogHint() {
+ return "需要读写权限以继续流程";
+ }
+
+ /**
+ * 权限请求结果回调
+ */
+ @Override
+ protected void permissionResult(boolean state, @Nullable String msg) {
+ Log.d("PermissionActivity", "state:" + state);
+ if (!state) return;
+ if (openFileRequestCode == FileConfig.readFileCode) {
+ //打开文件管理器
+ Intent mIntent = new Intent(Intent.ACTION_GET_CONTENT);
+ mIntent.addCategory(Intent.CATEGORY_OPENABLE);
+ mIntent.setType("application/json");
+ startActivityForResult(mIntent, 1001);
+ } else if (openFileRequestCode == FileConfig.writeFileCode) {
+ writeContentToFile();
+ }
+ }
+
+ private void backResult(String content, boolean writeState) {
+ if (callback == null) return;
+ Bundle mBundle = new Bundle();
+ if (openFileRequestCode == FileConfig.readFileCode) {
+ mBundle.putString("jsonContent", content);
+ } else if (openFileRequestCode == FileConfig.writeFileCode) {
+ mBundle.putBoolean("writeState", writeState);
+ }
+ callback.onResult(openFileRequestCode, mBundle);
+ callback = null;
+ finish();
+ }
+
+ private void writeContentToFile() {
+ File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+ boolean state;
+ if (!dir.exists()) dir.mkdirs();
+ File exportJson = new File(dir, "listen1_backup.json");
+ try {
+ if (exportJson.exists()) {
+ //如果文件存在,清空文件内容
+ FileWriter fileWrite = new FileWriter(exportJson);
+ fileWrite.write("");
+ fileWrite.flush();
+ fileWrite.close();
+ } else {
+ exportJson.createNewFile();
+ }
+ PrintWriter writer = new PrintWriter(new FileOutputStream(exportJson));
+ writer.print(FileConfig.content);
+ writer.close();
+ state = true;
+ } catch (IOException e) {
+ e.printStackTrace();
+ state = false;
+ }
+ backResult("", state);
+ }
+
+ private static ResultCallback callback = null;
+
+ public static void newInstance(Activity activity, int openFileRequestCode, @Nullable ResultCallback callback) {
+ OpenFileActivity.callback = callback;
+ Intent mIntent = new Intent(activity, OpenFileActivity.class);
+ mIntent.putExtra("OPEN_FILE_REQUEST_CODE", openFileRequestCode);
+ activity.startActivity(mIntent);
+ }
+}
diff --git a/android/app/src/main/java/com/listen1/app/PermissionActivity.java b/android/app/src/main/java/com/listen1/app/PermissionActivity.java
new file mode 100644
index 0000000..8718a22
--- /dev/null
+++ b/android/app/src/main/java/com/listen1/app/PermissionActivity.java
@@ -0,0 +1,95 @@
+package com.listen1.app;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
+
+public abstract class PermissionActivity extends AppCompatActivity {
+ private String requestHint = "该操作需要权限才能继续";
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ String hint = getDialogHint();
+ if (hint != null && !hint.isEmpty()) {
+ requestHint = hint;
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ if (requestCode != 1001) return;
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ permissionResult(true, null);
+ }
+ }
+
+ protected abstract String[] getPermissionArray();
+
+ protected abstract String getDialogHint();
+
+ /**
+ * 返回权限处理结果
+ *
+ * @param state true:权限获取成功
+ * @param msg 额外的消息字符串
+ */
+ protected abstract void permissionResult(boolean state, @Nullable String msg);
+
+ protected void checkPermission() {
+ if (getPermissionArray() == null || getPermissionArray().length == 0) {
+ throw new RuntimeException("权限不能为空!");
+ }
+ for (String permission : getPermissionArray()) {
+ if (ContextCompat.checkSelfPermission(getApplicationContext(), permission) != PackageManager.PERMISSION_DENIED)
+ continue;
+ if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
+ //用户之前拒绝了权限,且设置了不再提示
+ createDialog("已设置拒绝授予权限且不在显示,请前往设置手动设置权限", "确定", (dialog, which) -> {
+ //当用户还是想用APP,跳转到APP设置界面,由用户手动授予权限
+ Intent mIntent = new Intent(
+ Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ Uri.fromParts("package", getPackageName(), null)
+ );
+ startActivity(mIntent);
+ });
+ permissionResult(false, null);
+ } else {
+ createDialog(requestHint, "设置权限", (dialog, which) -> ActivityCompat.requestPermissions(this, getPermissionArray(), 1001));
+ }
+ return;
+ }
+ permissionResult(true, null);
+ }
+
+ /**
+ * 创建请求权限弹窗,当用户允许时触发权限请求流程
+ *
+ * @param msg 弹窗内容
+ * @param positiveBtn acceptBtn
+ */
+ private void createDialog(String msg, String positiveBtn, DialogInterface.OnClickListener listener) {
+ AlertDialog permissionDialog = new AlertDialog.Builder(this)
+ .setTitle("请求权限")
+ .setMessage(msg)
+ .setCancelable(false)
+ .setPositiveButton(positiveBtn, listener)
+ .setNegativeButton("取消", (dialog, which) -> finish())
+ .create();
+ if (permissionDialog.isShowing()) {
+ permissionDialog.dismiss();
+ }
+ permissionDialog.show();
+ }
+}
diff --git a/android/app/src/main/java/com/listen1/app/ResultCallback.java b/android/app/src/main/java/com/listen1/app/ResultCallback.java
new file mode 100644
index 0000000..a03a639
--- /dev/null
+++ b/android/app/src/main/java/com/listen1/app/ResultCallback.java
@@ -0,0 +1,7 @@
+package com.listen1.app;
+
+import android.os.Bundle;
+
+public interface ResultCallback {
+ void onResult(int requestCode, Bundle bundle);
+}
diff --git a/android/app/src/main/java/com/listen1/app/utils/FileConfig.java b/android/app/src/main/java/com/listen1/app/utils/FileConfig.java
new file mode 100644
index 0000000..deb03d9
--- /dev/null
+++ b/android/app/src/main/java/com/listen1/app/utils/FileConfig.java
@@ -0,0 +1,65 @@
+package com.listen1.app.utils;
+
+import android.os.Bundle;
+import android.util.Log;
+
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.listen1.app.OpenFileActivity;
+import com.listen1.app.ResultCallback;
+
+import javax.annotation.Nonnull;
+/**
+ * @Description: 歌曲配置的文件备份和恢复
+ * @Author: Void
+ * @CreateDate: 2023/1/11 15:22
+ * @UpdateDate: 2023/1/11 15:22
+ */
+public class FileConfig extends ReactContextBaseJavaModule implements ResultCallback {
+ public static final int readFileCode = 101;
+ public static final int writeFileCode = 102;
+ public static String content;
+ private Callback resultCallback;
+ private Callback errorCallback;
+
+ public FileConfig(@Nonnull ReactApplicationContext reactContext) {
+ super(reactContext);
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return "FileImportConfig";
+ }
+
+ @Override
+ public void onResult(int requestCode, Bundle bundle) {
+ if (requestCode == readFileCode) {
+ String content = bundle.getString("jsonContent");
+ if (content == null || content.isEmpty()) {
+ errorCallback.invoke("read fail");
+ } else {
+ Log.d(getName(), content);
+ resultCallback.invoke(content);
+ }
+ } else if (requestCode == writeFileCode) {
+ resultCallback.invoke(bundle.getBoolean("writeState"));
+ }
+ }
+
+ @ReactMethod
+ public void readFile(Callback resultCallback, Callback errorCallback) {
+ this.resultCallback = resultCallback;
+ this.errorCallback = errorCallback;
+ OpenFileActivity.newInstance(getCurrentActivity(), readFileCode, this);
+ }
+
+ @ReactMethod
+ public void writeFile(String content, Callback resultCallback) {
+ this.resultCallback = resultCallback;
+ FileConfig.content = content;
+ OpenFileActivity.newInstance(getCurrentActivity(), writeFileCode, this);
+ }
+}
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index 319eb0c..158876d 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -5,4 +5,18 @@
+
+
diff --git a/android/build.gradle b/android/build.gradle
index 3a1d305..3663e40 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -2,23 +2,30 @@
buildscript {
ext {
+ //在导入的项目中,如:react-native-music-control中有safeExtGet获取版本号
+ //以下代码用于统一项目编译版本
buildToolsVersion = "28.0.3"
- minSdkVersion = 16
- compileSdkVersion = 28
- targetSdkVersion = 28
+ minSdkVersion = 21
+ compileSdkVersion = 32
+ targetSdkVersion = 33
supportLibVersion = "28.0.0"
+ set('compileSdkVersion', compileSdkVersion)
+ set('buildToolsVersion', buildToolsVersion)
+ set('minSdkVersion', minSdkVersion)
+ set('targetSdkVersion', targetSdkVersion)
}
repositories {
google()
jcenter()
}
dependencies {
- classpath("com.android.tools.build:gradle:3.4.0")
+ classpath "com.android.tools.build:gradle:3.4.3"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
+def REACT_NATIVE_VERSION = new File(['node', '--print', "JSON.parse(require('fs').readFileSync(require.resolve('react-native/package.json'), 'utf-8')).version"].execute(null, rootDir).text.trim())
allprojects {
repositories {
@@ -29,5 +36,17 @@ allprojects {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
+ maven {
+ // Android JSC is installed from npm
+ url("$rootDir/../node_modules/jsc-android/dist")
+ }
+ }
+ configurations.all {
+ //低于0.65版本的‘react-native’需要加上这段代码,
+ //否则会出现类似:程序包com.facebook.react.common不存在 的错误
+ resolutionStrategy {
+ // Remove this override in 0.65+, as a proper fix is included in react-native itself.
+ force "com.facebook.react:react-native:" + REACT_NATIVE_VERSION
+ }
}
}
diff --git a/android/gradle.properties b/android/gradle.properties
index 2adc8e6..fa157e1 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -10,7 +10,7 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
-# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
@@ -19,4 +19,6 @@
MYAPP_UPLOAD_STORE_FILE=my-release-key.keystore
MYAPP_UPLOAD_KEY_ALIAS=my-key-alias
MYAPP_UPLOAD_STORE_PASSWORD=lovemusic
-MYAPP_UPLOAD_KEY_PASSWORD=lovemusic
\ No newline at end of file
+MYAPP_UPLOAD_KEY_PASSWORD=lovemusic
+android.useAndroidX=true
+android.enableJetifier=true
\ No newline at end of file
diff --git a/android/settings.gradle b/android/settings.gradle
index ef6c9bc..d507178 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -1,4 +1,10 @@
rootProject.name = 'Listen1'
+include ':react-native-vector-icons'
+project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
+include ':react-native-screens'
+project(':react-native-screens').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-screens/android')
+include ':@react-native-community_toolbar-android'
+project(':@react-native-community_toolbar-android').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/toolbar-android/android')
include ':@react-native-community_async-storage'
project(':@react-native-community_async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/async-storage/android')
include ':react-native-music-control'
diff --git a/package.json b/package.json
index 07e8af5..7560a0d 100755
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"@react-native-community/async-storage": "^1.12.1",
"@react-native-community/toolbar-android": "^0.1.0-rc.2",
"deprecated-react-native-listview": "^0.0.5",
+ "jetifier": "^2.0.0",
"md5": "^2.2.1",
"query-string": "^6.8.1",
"react": "16.8.3",
diff --git a/src/views/setting/export-local.screen.js b/src/views/setting/export-local.screen.js
index a8af577..7048de1 100644
--- a/src/views/setting/export-local.screen.js
+++ b/src/views/setting/export-local.screen.js
@@ -1,5 +1,6 @@
import React from 'react';
-import { ScrollView, Clipboard, Button } from 'react-native';
+import { ScrollView, Clipboard, View, Platform, NativeModules} from 'react-native';
+import { Button } from 'react-native-elements';
import { connect } from 'react-redux';
import styled, { withTheme } from 'styled-components';
import StateJsonConvert from '../../modules/state-json-convert';
@@ -25,8 +26,9 @@ class ExportLocal extends React.Component {
};
constructor(props) {
super(props);
- this.state = { jsonString: '' };
+ this.state = { jsonString: '' , deviceOS: Platform.OS};
this.onPressCopy = this.onPressCopy.bind(this);
+ this.onExportConfigToFile = this.onExportConfigToFile.bind(this);
}
componentDidMount() {
// generate backup json
@@ -39,8 +41,18 @@ class ExportLocal extends React.Component {
}
onPressCopy = () => {
Clipboard.setString(this.state.jsonString);
+ console.log(`render ${this.state.jsonString}`);
showToast('已复制到剪切板');
};
+ onExportConfigToFile=()=>{
+ NativeModules.FileImportConfig.writeFile(this.state.jsonString,(writeState)=>{
+ if (writeState) {
+ showToast('备份成功: /storage/emulated/0/Download/listen1_backup.json');
+ }else{
+ showToast('备份失败');
+ }
+ })
+ };
render() {
// console.log(`render ${this.constructor.name}`);
@@ -50,6 +62,11 @@ class ExportLocal extends React.Component {
{this.state.jsonString}
+
+ {(this.state.deviceOS == 'android')?(
+
+ ):null}
+
备份方法:点击一键复制后,将内容粘贴到文本文件或笔记中,恢复时在恢复窗口粘贴回来就可以了。
diff --git a/src/views/setting/import-local.screen.js b/src/views/setting/import-local.screen.js
index 42e26ed..21162e2 100644
--- a/src/views/setting/import-local.screen.js
+++ b/src/views/setting/import-local.screen.js
@@ -1,5 +1,5 @@
import React from 'react';
-import { ScrollView, Clipboard } from 'react-native';
+import { ScrollView, Clipboard, View, Platform, NativeModules } from 'react-native';
import { Button } from 'react-native-elements';
import { connect } from 'react-redux';
import styled, { withTheme } from 'styled-components';
@@ -26,15 +26,16 @@ class ImportLocal extends React.Component {
};
constructor(props) {
super(props);
- this.state = { jsonString: '', isValidJson: false };
+ this.state = { jsonString: '', isValidJson: false , deviceOS: Platform.OS};
this.onPressPaste = this.onPressPaste.bind(this);
this.onPressRecover = this.onPressRecover.bind(this);
+ this.onPressImportFile = this.onPressImportFile.bind(this);
}
onPressPaste = () => {
Clipboard.getString().then(jsonString => {
- try {
- JSON.parse(jsonString);
+ try {
+ JSON.parse(jsonString);
} catch {
this.setState({ jsonString: '', isValidJson: false });
@@ -52,6 +53,17 @@ class ImportLocal extends React.Component {
this.props.dispatch(recoverData(state));
showToast('恢复成功,请返回');
};
+
+ onPressImportFile = () => {
+ NativeModules.FileImportConfig.readFile((jsonString) => {
+ this.setState({ jsonString, isValidJson: true });
+ return showToast('文件导入成功');
+ },
+ (errorInfo) => {
+ return showToast('从文件导入失败,文件内容错误');
+ });
+ };
+
render() {
// console.log(`render ${this.constructor.name}`);
@@ -71,6 +83,9 @@ class ImportLocal extends React.Component {
/>
)}
+ {(!this.state.isValidJson && this.state.deviceOS == 'android') ? (
+
+ ) : null}
恢复方法:复制之前备份的文本,点击“从剪切板粘贴”,
再点击“恢复”就可以了。