From d6ca6d7fa55c6434f7900d54f4157ae1c6b9f270 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AD=99=E5=A8=87?=
Date: Mon, 26 Feb 2024 11:26:41 +0800
Subject: [PATCH] add iOS support
---
README.md | 1 +
ios/Runner.xcodeproj/project.pbxproj | 7 ++---
ios/Runner/AppDelegate.swift | 47 +++++++++++++++++++++++-----
ios/Runner/Info.plist | 3 ++
lib/main.dart | 2 --
lib/pages/files_page.dart | 2 ++
lib/tools/ios_platform.dart | 21 +++++++++++++
7 files changed, 70 insertions(+), 13 deletions(-)
create mode 100644 lib/tools/ios_platform.dart
diff --git a/README.md b/README.md
index 2df343c..97710c5 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@ todo:
- ~~Convert, including case convert, Chinese simp/trad/pinyin convert, Latin/Cyrillic script transliteration~~.(Done.)
- ~~Incremental renaming: for example, RenamerFile-1, RenamerFile-2, RenamerFile-3, RenamerFile-4, ...~~.(Done.)
- Rules re-editing.
+- Implement iOS renamer with specific code and Platform channel, references: [Writing custom platform-specific code](https://docs.flutter.dev/platform-integration/platform-channels?tab=type-mappings-swift-tab#type-mappings-swift-tab), [Providing access to directories](https://developer.apple.com/documentation/uikit/view_controllers/providing_access_to_directories), [juanmartin/renamerApp-ios](https://github.com/juanmartin/renamerApp-ios)
# Screenshots
## Desktop
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 87927dc..d1e9320 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -97,7 +97,6 @@
A40B1E21F74A722135CAF778 /* Pods-RunnerTests.release.xcconfig */,
2581B69E8F1CCD428434EC5E /* Pods-RunnerTests.profile.xcconfig */,
);
- name = Pods;
path = Pods;
sourceTree = "";
};
@@ -475,7 +474,7 @@
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Renamer;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
- IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -661,7 +660,7 @@
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Renamer;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
- IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -687,7 +686,7 @@
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Renamer;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
- IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift
index 70693e4..93f479a 100644
--- a/ios/Runner/AppDelegate.swift
+++ b/ios/Runner/AppDelegate.swift
@@ -3,11 +3,44 @@ import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
- override func application(
- _ application: UIApplication,
- didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
- ) -> Bool {
- GeneratedPluginRegistrant.register(with: self)
- return super.application(application, didFinishLaunchingWithOptions: launchOptions)
- }
+ override func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+ ) -> Bool {
+ GeneratedPluginRegistrant.register(with: self)
+ let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
+ let filePickerChannel = FlutterMethodChannel(name: "net.sunjiao.renamer/picker",
+ binaryMessenger: controller.binaryMessenger)
+ filePickerChannel.setMethodCallHandler({
+ [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
+ // This method is invoked on the UI thread.
+ if call.method == "dirAccess" {
+ self.dirAccess(result: result)
+ } else if call.method == "renameFile" {
+ self.renameFile(result: result)
+ } else {
+ result(FlutterMethodNotImplemented)
+ }
+ })
+
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+
+ private func dirAccess(result: @escaping FlutterResult) {
+ let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.folder])
+ documentPicker.delegate = self
+ window?.rootViewController?.present(documentPicker, animated: true, completion: nil)
+ }
+
+ private func renameFile(result: @escaping FlutterResult) {
+ return
+ }
+}
+
+extension AppDelegate: UIDocumentPickerDelegate {
+ func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
+ if let url = urls.first {
+ // result(url.path)
+ }
+ }
}
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 9749aba..b532311 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -64,5 +64,8 @@
NSPhotoLibraryUsageDescription
Explain why your app uses photo library
+ NSDocumentsFolderUsageDescription
+ Explain why your app uses
+
diff --git a/lib/main.dart b/lib/main.dart
index ba9587c..9bdc68c 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -100,8 +100,6 @@ class AppPage extends StatelessWidget {
return;
}
}
-
-
}
void _permissionRequest(BuildContext context) => showDialog(
diff --git a/lib/pages/files_page.dart b/lib/pages/files_page.dart
index 70348f4..c23dd15 100644
--- a/lib/pages/files_page.dart
+++ b/lib/pages/files_page.dart
@@ -51,6 +51,8 @@ class FilesPageState extends State {
} else {
return;
}
+ } else if (Platform.isIOS) {
+
} else {
FilePickerResult? result = await FilePicker.platform.pickFiles(allowMultiple: true);
if (result != null) {
diff --git a/lib/tools/ios_platform.dart b/lib/tools/ios_platform.dart
new file mode 100644
index 0000000..d1d2f96
--- /dev/null
+++ b/lib/tools/ios_platform.dart
@@ -0,0 +1,21 @@
+import 'package:flutter/services.dart';
+
+class PlatformFilePicker {
+ static const MethodChannel _channel = MethodChannel('net.sunjiao.renamer/picker');
+
+ static Future dirAccess() async {
+ try {
+ await _channel.invokeMethod('dirAccess');
+ } on PlatformException catch (e) {
+ // show error message
+ }
+ }
+
+ static Future renameFile() async {
+ try {
+ await _channel.invokeMethod('renameFile');
+ } on PlatformException catch (e) {
+ // show error message
+ }
+ }
+}