From 63bea8b8415801c59228e4b0da3e14c9f6aa7fc4 Mon Sep 17 00:00:00 2001 From: sorairo Date: Sun, 4 Feb 2024 22:58:56 +0900 Subject: [PATCH] =?UTF-8?q?ShareExtension=E3=81=8B=E3=82=89=E5=85=B1?= =?UTF-8?q?=E6=9C=89=E3=81=97=E3=81=9F=E3=82=82=E3=81=AE=E3=82=92=E8=AA=AD?= =?UTF-8?q?=E3=81=BF=E5=87=BA=E3=81=9B=E3=82=8B=E3=81=A8=E3=81=93=E3=82=8D?= =?UTF-8?q?=E3=81=BE=E3=81=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios/Podfile | 8 +- ios/Podfile.lock | 2 +- ios/Runner.xcodeproj/project.pbxproj | 2 +- ios/ShareExtension/ShareViewController.swift | 605 ++++++++---------- .../share_extension_page.dart | 55 +- 5 files changed, 297 insertions(+), 375 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index 7fd46e3c4..b35dce65c 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -34,6 +34,10 @@ target 'Runner' do use_modular_headers! flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + + target 'ShareExtension' do + inherit! :search_paths + end end post_install do |installer| @@ -48,8 +52,4 @@ post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) end -end -target :ShareExtension do - use_frameworks! - pod 'shared_preference_app_group', path: '.symlinks/plugins/shared_preference_app_group/ios' end \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 6e8ef9b85..bbc3d00df 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -225,6 +225,6 @@ SPEC CHECKSUMS: wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47 webview_flutter_wkwebview: 4f3e50f7273d31e5500066ed267e3ae4309c5ae4 -PODFILE CHECKSUM: b6cba02e8306bb2b2eadb891f9670d202cef6ace +PODFILE CHECKSUM: bd49fdcc50731fff63770138ae17792f83db3fa4 COCOAPODS: 1.14.3 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 87f3964e2..a084036b9 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -358,7 +358,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; }; 72427D6E1FCF5EC68D493D27 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; diff --git a/ios/ShareExtension/ShareViewController.swift b/ios/ShareExtension/ShareViewController.swift index 096230a01..ab61a46f2 100644 --- a/ios/ShareExtension/ShareViewController.swift +++ b/ios/ShareExtension/ShareViewController.swift @@ -1,10 +1,23 @@ import UIKit import Flutter - +import Social +import MobileCoreServices +import Photos class ShareViewController: UIViewController, FlutterPluginRegistry { + private let imageContentType = kUTTypeImage as String + private let videoContentType = kUTTypeMovie as String + private let textContentType = kUTTypeText as String + private let urlContentType = kUTTypeURL as String + private let fileURLType = kUTTypeFileURL as String; + private let sharedKey = "ShareKey" + private let hostAppBundleIdentifier = "info.shiosyakeyakini.miria" + + private var shareText: [String] = [] + private var shareFiles: [SharedMediaFile] = [] + + private let flutterViewController: FlutterViewController = FlutterViewController(project: nil, initialRoute: "/share-extension", nibName: nil, bundle: nil) - private var flutterViewController: FlutterViewController = FlutterViewController(project: nil, initialRoute: "/share-extension", nibName: nil, bundle: nil) @objc func registrar(forPlugin pluginKey: String) -> FlutterPluginRegistrar? { return flutterViewController.registrar(forPlugin: pluginKey) @@ -20,359 +33,251 @@ class ShareViewController: UIViewController, FlutterPluginRegistry { override func viewDidLoad() { super.viewDidLoad() - ShareExtensionPluginRegistrant.register(with: self) - showFlutter() - } + + // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments. + if let content = extensionContext!.inputItems[0] as? NSExtensionItem { + if let contents = content.attachments { + for (index, attachment) in (contents).enumerated() { + if attachment.hasItemConformingToTypeIdentifier(imageContentType) { + handleImages(content: content, attachment: attachment, index: index) + } else if attachment.hasItemConformingToTypeIdentifier(textContentType) { + handleText(content: content, attachment: attachment, index: index) + } else if attachment.hasItemConformingToTypeIdentifier(fileURLType) { + handleFiles(content: content, attachment: attachment, index: index) + } else if attachment.hasItemConformingToTypeIdentifier(urlContentType) { + let attributedTitle = content.attributedTitle?.string + let attributedContent = content.attributedContentText?.string + handleUrl(content: content, attachment: attachment, index: index, title: attributedTitle ?? attributedContent); + } else if attachment.hasItemConformingToTypeIdentifier(videoContentType) { + handleVideos(content: content, attachment: attachment, index: index) + } + } - func showFlutter() { - //self.preferredContentSize = CGSize(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.height * 0.8) - self.view.frame = CGRect(x: 0, y: 0, width:UIScreen.main.bounds.size.width, height:UIScreen.main.bounds.size.height * 0.8) + } + } + ShareExtensionPluginRegistrant.register(with: self) addChild(flutterViewController) view.addSubview(flutterViewController.view) flutterViewController.view.frame = view.bounds } -} + + private func save() { + let userDefaults = UserDefaults(suiteName: "group.\(self.hostAppBundleIdentifier)") + let encoder = JSONEncoder() + let json = try? encoder.encode(SendData(text: self.shareText, files: self.shareFiles)) + guard let encoded = json else { + return + } + userDefaults?.set(String(data: encoded, encoding: .utf8), forKey: self.sharedKey) + userDefaults?.synchronize() + } + + private func handleText (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { + attachment.loadItem(forTypeIdentifier: textContentType, options: nil) { [weak self] data, error in + + if error == nil, let item = data as? String, let this = self { + this.shareText.append(item) + if index == (content.attachments?.count)! - 1 { + this.save() + } + } + } + } + + private func handleUrl (content: NSExtensionItem, attachment: NSItemProvider, index: Int, title: String?) { + attachment.loadItem(forTypeIdentifier: urlContentType, options: nil) { [weak self] data, error in + + if error == nil, let item = data as? URL, let this = self { + let text: String + if(title != nil) { + text = "[\(title ?? "")](\(item.absoluteString))" + } else { + text = item.absoluteString + } + this.shareText.append(text) + if index == (content.attachments?.count)! - 1 { + this.save() + } + } + } + } + + private func handleImages (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { + attachment.loadItem(forTypeIdentifier: imageContentType, options: nil) { [weak self] data, error in + + if error == nil, let url = data as? URL, let this = self { + + // Always copy + let fileName = this.getFileName(from: url, type: .image) + let newPath = FileManager.default + .containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")! + .appendingPathComponent(fileName) + let copied = this.copyFile(at: url, to: newPath) + if(copied) { + this.shareFiles.append(SharedMediaFile(path: newPath.absoluteString, thumbnail: nil, duration: nil, type: .image)) + } + if index == (content.attachments?.count)! - 1 { + this.save() + } + } + } + } + + private func handleVideos (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { + attachment.loadItem(forTypeIdentifier: videoContentType, options: nil) { [weak self] data, error in + + if error == nil, let url = data as? URL, let this = self { + + // Always copy + let fileName = this.getFileName(from: url, type: .video) + let newPath = FileManager.default + .containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")! + .appendingPathComponent(fileName) + let copied = this.copyFile(at: url, to: newPath) + if(copied) { + guard let sharedFile = this.getSharedMediaFile(forVideo: newPath) else { + return + } + this.shareFiles.append(sharedFile) + } + if index == (content.attachments?.count)! - 1 { + this.save() + } + } + } + } + + private func handleFiles (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { + attachment.loadItem(forTypeIdentifier: fileURLType, options: nil) { [weak self] data, error in + if error == nil, let url = data as? URL, let this = self { + // Always copy + let fileName = this.getFileName(from :url, type: .file) + let newPath = FileManager.default + .containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")! + .appendingPathComponent(fileName) + let copied = this.copyFile(at: url, to: newPath) + if (copied) { + this.shareFiles.append(SharedMediaFile(path: newPath.absoluteString, thumbnail: nil, duration: nil, type: .file)) + } + if index == (content.attachments?.count)! - 1 { + this.save() + } + } + } + } + func getExtension(from url: URL, type: SharedMediaType) -> String { + let parts = url.lastPathComponent.components(separatedBy: ".") + var ex: String? = nil + if (parts.count > 1) { + ex = parts.last + } + + if (ex == nil) { + switch type { + case .image: + ex = "PNG" + case .video: + ex = "MP4" + case .file: + ex = "TXT" + } + } + return ex ?? "Unknown" + } + + func getFileName(from url: URL, type: SharedMediaType) -> String { + var name = url.lastPathComponent + + if (name.isEmpty) { + name = UUID().uuidString + "." + getExtension(from: url, type: type) + } + + return name + } + + func copyFile(at srcURL: URL, to dstURL: URL) -> Bool { + do { + if FileManager.default.fileExists(atPath: dstURL.path) { + try FileManager.default.removeItem(at: dstURL) + } + try FileManager.default.copyItem(at: srcURL, to: dstURL) + } catch (let error) { + print("Cannot copy item at \(srcURL) to \(dstURL): \(error)") + return false + } + return true + } + private func getSharedMediaFile(forVideo: URL) -> SharedMediaFile? { + let asset = AVAsset(url: forVideo) + let duration = (CMTimeGetSeconds(asset.duration) * 1000).rounded() + let thumbnailPath = getThumbnailPath(for: forVideo) + + if FileManager.default.fileExists(atPath: thumbnailPath.path) { + return SharedMediaFile(path: forVideo.absoluteString, thumbnail: thumbnailPath.absoluteString, duration: duration, type: .video) + } + + var saved = false + let assetImgGenerate = AVAssetImageGenerator(asset: asset) + assetImgGenerate.appliesPreferredTrackTransform = true + // let scale = UIScreen.main.scale + assetImgGenerate.maximumSize = CGSize(width: 360, height: 360) + do { + let img = try assetImgGenerate.copyCGImage(at: CMTimeMakeWithSeconds(600, preferredTimescale: Int32(1.0)), actualTime: nil) + try UIImage.pngData(UIImage(cgImage: img))()?.write(to: thumbnailPath) + saved = true + } catch { + saved = false + } + + return saved ? SharedMediaFile(path: forVideo.absoluteString, thumbnail: thumbnailPath.absoluteString, duration: duration, type: .video) : nil + + } + + private func getThumbnailPath(for url: URL) -> URL { + let fileName = Data(url.lastPathComponent.utf8).base64EncodedString().replacingOccurrences(of: "==", with: "") + let path = FileManager.default + .containerURL(forSecurityApplicationGroupIdentifier: "group.\(hostAppBundleIdentifier)")! + .appendingPathComponent("\(fileName).jpg") + return path + } + + + class SharedMediaFile: Codable { + var path: String; // can be image, video or url path. It can also be text content + var thumbnail: String?; // video thumbnail + var duration: Double?; // video duration in milliseconds + var type: SharedMediaType; + + + init(path: String, thumbnail: String?, duration: Double?, type: SharedMediaType) { + self.path = path + self.thumbnail = thumbnail + self.duration = duration + self.type = type + } + + // Debug method to print out SharedMediaFile details in the console + func toString() { + print("[SharedMediaFile] \n\tpath: \(self.path)\n\tthumbnail: \(self.thumbnail)\n\tduration: \(self.duration)\n\ttype: \(self.type)") + } + } + + struct SendData: Encodable { + let text: [String] + let files: [SharedMediaFile] + } + + enum SharedMediaType: Int, Codable { + case image + case video + case file + } + + func toData(data: [SharedMediaFile]) -> Data { + let encodedData = try? JSONEncoder().encode(data) + return encodedData! + } +} -// import UIKit -// import Social -// import MobileCoreServices -// import Photos -// -// class ShareViewController: SLComposeServiceViewController { -// // TODO: IMPORTANT: This should be your host app bundle identifier -// let hostAppBundleIdentifier = "info.shiosyakeyakini.miria" -// let sharedKey = "ShareKey" -// var sharedMedia: [SharedMediaFile] = [] -// var sharedText: [String] = [] -// let imageContentType = kUTTypeImage as String -// let videoContentType = kUTTypeMovie as String -// let textContentType = kUTTypeText as String -// let urlContentType = kUTTypeURL as String -// let fileURLType = kUTTypeFileURL as String; -// -// override func isContentValid() -> Bool { -// return true -// } -// -// override func viewDidLoad() { -// super.viewDidLoad(); -// } -// -// override func viewDidAppear(_ animated: Bool) { -// super.viewDidAppear(animated) -// -// // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments. -// if let content = extensionContext!.inputItems[0] as? NSExtensionItem { -// if let contents = content.attachments { -// for (index, attachment) in (contents).enumerated() { -// if attachment.hasItemConformingToTypeIdentifier(imageContentType) { -// handleImages(content: content, attachment: attachment, index: index) -// } else if attachment.hasItemConformingToTypeIdentifier(textContentType) { -// handleText(content: content, attachment: attachment, index: index) -// } else if attachment.hasItemConformingToTypeIdentifier(fileURLType) { -// handleFiles(content: content, attachment: attachment, index: index) -// } else if attachment.hasItemConformingToTypeIdentifier(urlContentType) { -// let attributedTitle = content.attributedTitle?.string -// let attributedContent = content.attributedContentText?.string -// handleUrl(content: content, attachment: attachment, index: index, title: attributedTitle ?? attributedContent); -// } else if attachment.hasItemConformingToTypeIdentifier(videoContentType) { -// handleVideos(content: content, attachment: attachment, index: index) -// } -// } -// } -// } -// } -// -// override func didSelectPost() { -// print("didSelectPost"); -// } -// -// override func configurationItems() -> [Any]! { -// // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here. -// return [] -// } -// -// private func handleText (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { -// attachment.loadItem(forTypeIdentifier: textContentType, options: nil) { [weak self] data, error in -// -// if error == nil, let item = data as? String, let this = self { -// -// this.sharedText.append(item) -// -// // If this is the last item, save imagesData in userDefaults and redirect to host app -// if index == (content.attachments?.count)! - 1 { -// let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)") -// userDefaults?.set(this.sharedText, forKey: this.sharedKey) -// userDefaults?.synchronize() -// this.redirectToHostApp(type: .text) -// } -// -// } else { -// self?.dismissWithError() -// } -// } -// } -// -// private func handleUrl (content: NSExtensionItem, attachment: NSItemProvider, index: Int, title: String?) { -// attachment.loadItem(forTypeIdentifier: urlContentType, options: nil) { [weak self] data, error in -// -// if error == nil, let item = data as? URL, let this = self { -// this.sharedText.removeAll() -// if(title != nil) { -// this.sharedText.append("[\(title ?? "")](\(item.absoluteString))") -// } else { -// this.sharedText.append(item.absoluteString) -// } -// -// // If this is the last item, save imagesData in userDefaults and redirect to host app -// if index == (content.attachments?.count)! - 1 { -// let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)") -// userDefaults?.set(this.sharedText, forKey: this.sharedKey) -// userDefaults?.synchronize() -// this.redirectToHostApp(type: .text) -// } -// -// } else { -// self?.dismissWithError() -// } -// } -// } -// -// private func handleImages (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { -// attachment.loadItem(forTypeIdentifier: imageContentType, options: nil) { [weak self] data, error in -// -// if error == nil, let url = data as? URL, let this = self { -// -// // Always copy -// let fileName = this.getFileName(from: url, type: .image) -// let newPath = FileManager.default -// .containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")! -// .appendingPathComponent(fileName) -// let copied = this.copyFile(at: url, to: newPath) -// if(copied) { -// this.sharedMedia.append(SharedMediaFile(path: newPath.absoluteString, thumbnail: nil, duration: nil, type: .image)) -// } -// -// // If this is the last item, save imagesData in userDefaults and redirect to host app -// if index == (content.attachments?.count)! - 1 { -// let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)") -// userDefaults?.set(this.toData(data: this.sharedMedia), forKey: this.sharedKey) -// userDefaults?.synchronize() -// this.redirectToHostApp(type: .media) -// } -// -// } else { -// self?.dismissWithError() -// } -// } -// } -// -// private func handleVideos (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { -// attachment.loadItem(forTypeIdentifier: videoContentType, options: nil) { [weak self] data, error in -// -// if error == nil, let url = data as? URL, let this = self { -// -// // Always copy -// let fileName = this.getFileName(from: url, type: .video) -// let newPath = FileManager.default -// .containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")! -// .appendingPathComponent(fileName) -// let copied = this.copyFile(at: url, to: newPath) -// if(copied) { -// guard let sharedFile = this.getSharedMediaFile(forVideo: newPath) else { -// return -// } -// this.sharedMedia.append(sharedFile) -// } -// -// // If this is the last item, save imagesData in userDefaults and redirect to host app -// if index == (content.attachments?.count)! - 1 { -// let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)") -// userDefaults?.set(this.toData(data: this.sharedMedia), forKey: this.sharedKey) -// userDefaults?.synchronize() -// this.redirectToHostApp(type: .media) -// } -// -// } else { -// self?.dismissWithError() -// } -// } -// } -// -// private func handleFiles (content: NSExtensionItem, attachment: NSItemProvider, index: Int) { -// attachment.loadItem(forTypeIdentifier: fileURLType, options: nil) { [weak self] data, error in -// -// if error == nil, let url = data as? URL, let this = self { -// -// // Always copy -// let fileName = this.getFileName(from :url, type: .file) -// let newPath = FileManager.default -// .containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")! -// .appendingPathComponent(fileName) -// let copied = this.copyFile(at: url, to: newPath) -// if (copied) { -// this.sharedMedia.append(SharedMediaFile(path: newPath.absoluteString, thumbnail: nil, duration: nil, type: .file)) -// } -// -// if index == (content.attachments?.count)! - 1 { -// let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)") -// userDefaults?.set(this.toData(data: this.sharedMedia), forKey: this.sharedKey) -// userDefaults?.synchronize() -// this.redirectToHostApp(type: .file) -// } -// -// } else { -// self?.dismissWithError() -// } -// } -// } -// -// private func dismissWithError() { -// print("[ERROR] Error loading data!") -// let alert = UIAlertController(title: "Error", message: "Error loading data", preferredStyle: .alert) -// -// let action = UIAlertAction(title: "Error", style: .cancel) { _ in -// self.dismiss(animated: true, completion: nil) -// } -// -// alert.addAction(action) -// present(alert, animated: true, completion: nil) -// extensionContext!.completeRequest(returningItems: [], completionHandler: nil) -// } -// -// private func redirectToHostApp(type: RedirectType) { -// let url = URL(string: "ShareMedia://dataUrl=\(sharedKey)#\(type)") -// var responder = self as UIResponder? -// let selectorOpenURL = sel_registerName("openURL:") -// -// while (responder != nil) { -// if (responder?.responds(to: selectorOpenURL))! { -// let _ = responder?.perform(selectorOpenURL, with: url) -// } -// responder = responder!.next -// } -// extensionContext!.completeRequest(returningItems: [], completionHandler: nil) -// } -// -// enum RedirectType { -// case media -// case text -// case file -// } -// -// func getExtension(from url: URL, type: SharedMediaType) -> String { -// let parts = url.lastPathComponent.components(separatedBy: ".") -// var ex: String? = nil -// if (parts.count > 1) { -// ex = parts.last -// } -// -// if (ex == nil) { -// switch type { -// case .image: -// ex = "PNG" -// case .video: -// ex = "MP4" -// case .file: -// ex = "TXT" -// } -// } -// return ex ?? "Unknown" -// } -// -// func getFileName(from url: URL, type: SharedMediaType) -> String { -// var name = url.lastPathComponent -// -// if (name.isEmpty) { -// name = UUID().uuidString + "." + getExtension(from: url, type: type) -// } -// -// return name -// } -// -// func copyFile(at srcURL: URL, to dstURL: URL) -> Bool { -// do { -// if FileManager.default.fileExists(atPath: dstURL.path) { -// try FileManager.default.removeItem(at: dstURL) -// } -// try FileManager.default.copyItem(at: srcURL, to: dstURL) -// } catch (let error) { -// print("Cannot copy item at \(srcURL) to \(dstURL): \(error)") -// return false -// } -// return true -// } -// -// private func getSharedMediaFile(forVideo: URL) -> SharedMediaFile? { -// let asset = AVAsset(url: forVideo) -// let duration = (CMTimeGetSeconds(asset.duration) * 1000).rounded() -// let thumbnailPath = getThumbnailPath(for: forVideo) -// -// if FileManager.default.fileExists(atPath: thumbnailPath.path) { -// return SharedMediaFile(path: forVideo.absoluteString, thumbnail: thumbnailPath.absoluteString, duration: duration, type: .video) -// } -// -// var saved = false -// let assetImgGenerate = AVAssetImageGenerator(asset: asset) -// assetImgGenerate.appliesPreferredTrackTransform = true -// // let scale = UIScreen.main.scale -// assetImgGenerate.maximumSize = CGSize(width: 360, height: 360) -// do { -// let img = try assetImgGenerate.copyCGImage(at: CMTimeMakeWithSeconds(600, preferredTimescale: Int32(1.0)), actualTime: nil) -// try UIImage.pngData(UIImage(cgImage: img))()?.write(to: thumbnailPath) -// saved = true -// } catch { -// saved = false -// } -// -// return saved ? SharedMediaFile(path: forVideo.absoluteString, thumbnail: thumbnailPath.absoluteString, duration: duration, type: .video) : nil -// -// } -// -// private func getThumbnailPath(for url: URL) -> URL { -// let fileName = Data(url.lastPathComponent.utf8).base64EncodedString().replacingOccurrences(of: "==", with: "") -// let path = FileManager.default -// .containerURL(forSecurityApplicationGroupIdentifier: "group.\(hostAppBundleIdentifier)")! -// .appendingPathComponent("\(fileName).jpg") -// return path -// } -// -// class SharedMediaFile: Codable { -// var path: String; // can be image, video or url path. It can also be text content -// var thumbnail: String?; // video thumbnail -// var duration: Double?; // video duration in milliseconds -// var type: SharedMediaType; -// -// -// init(path: String, thumbnail: String?, duration: Double?, type: SharedMediaType) { -// self.path = path -// self.thumbnail = thumbnail -// self.duration = duration -// self.type = type -// } -// -// // Debug method to print out SharedMediaFile details in the console -// func toString() { -// print("[SharedMediaFile] \n\tpath: \(self.path)\n\tthumbnail: \(self.thumbnail)\n\tduration: \(self.duration)\n\ttype: \(self.type)") -// } -// } -// -// enum SharedMediaType: Int, Codable { -// case image -// case video -// case file -// } -// -// func toData(data: [SharedMediaFile]) -> Data { -// let encodedData = try? JSONEncoder().encode(data) -// return encodedData! -// } -// } -// -// extension Array { -// subscript (safe index: UInt) -> Element? { -// return Int(index) < count ? self[Int(index)] : nil -// } -// } diff --git a/lib/view/share_extension_page/share_extension_page.dart b/lib/view/share_extension_page/share_extension_page.dart index 2a6089663..05b05e597 100644 --- a/lib/view/share_extension_page/share_extension_page.dart +++ b/lib/view/share_extension_page/share_extension_page.dart @@ -4,32 +4,49 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shared_preference_app_group/shared_preference_app_group.dart'; @RoutePage() -class ShareExtensionPage extends ConsumerWidget { +class ShareExtensionPage extends ConsumerStatefulWidget { const ShareExtensionPage({super.key}); @override - Widget build(BuildContext context, WidgetRef ref) { + ConsumerState createState() => + ShareExtensionPageState(); +} + +class ShareExtensionPageState extends ConsumerState { + var sharedPreference = ""; + var sharedData = ""; + String? error; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + Future(() async { + try { + await SharedPreferenceAppGroup.setAppGroup( + "group.info.shiosyakeyakini.miria"); + sharedPreference = + await SharedPreferenceAppGroup.get("account_settings") as String? ?? + ""; + sharedData = + await SharedPreferenceAppGroup.get("ShareKey") as String? ?? ""; + await SharedPreferenceAppGroup.setString("ShareKey", ""); + setState(() {}); + } catch (e) { + setState(() { + error = e.toString(); + }); + } + }); + } + + @override + Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Share Extension Page Test"), ), - body: FutureBuilder( - future: Future(() async { - await SharedPreferenceAppGroup.setAppGroup( - "group.info.shiosyakeyakini.miria"); - return await SharedPreferenceAppGroup.get("account_settings") - as String?; - }), - builder: (context, snapshot) { - if (snapshot.hasData) { - return Text(snapshot.requireData ?? "no data"); - } else if (snapshot.hasError) { - return Text("${snapshot.error}\n${snapshot.stackTrace}"); - } else { - return const CircularProgressIndicator(); - } - }, - ), + body: Text(error ?? + "SharedPreference: $sharedPreference\n共有されたデータ: $sharedData"), ); } }