Open StepZEROsk opened 1 year ago
hi i dont have solution but i am not able to do successfully on ios can you please tell how you add and how you create group id or if you dont mind can you share code please
Hello,
thankYou for your answer.
Im using your code from doc. See details below.
AppDelegate.swift `import UIKit import Capacitor import SendIntent
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let store = ShareStore.store
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
var success = true
if CAPBridge.handleOpenUrl(url, options) {
success = ApplicationDelegateProxy.shared.application(app, open: url, options: options)
}
guard let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true),
let params = components.queryItems else {
return false
}
let titles = params.filter { $0.name == "title" }
let descriptions = params.filter { $0.name == "description" }
let types = params.filter { $0.name == "type" }
let urls = params.filter { $0.name == "url" }
store.shareItems.removeAll()
if(titles.count > 0){
for index in 0...titles.count-1 {
var shareItem: JSObject = JSObject()
shareItem["title"] = titles[index].value!
shareItem["description"] = descriptions[index].value!
shareItem["type"] = types[index].value!
shareItem["url"] = urls[index].value!
store.shareItems.append(shareItem)
}
}
dump(store.shareItems)
store.processed = false
let nc = NotificationCenter.default
nc.post(name: Notification.Name("triggerSendIntent"), object: nil )
return success
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
// Called when the app was launched with an activity, including Universal Links.
// Feel free to add additional processing here, but if you want the App API to support
// tracking app url opens, make sure to keep this call
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
}
} ` ShareViewController.swift
` import MobileCoreServices import Social import UIKit
class ShareItem {
public var title: String?
public var type: String?
public var url: String?
}
class ShareViewController: UIViewController {
private var shareItems: [ShareItem] = []
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
private func sendData() {
let queryItems = shareItems.map {
[
URLQueryItem(
name: "title",
value: $0.title?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""),
URLQueryItem(name: "description", value: ""),
URLQueryItem(
name: "type",
value: $0.type?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""),
URLQueryItem(
name: "url",
value: $0.url?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""),
]
}.flatMap({ $0 })
var urlComps = URLComponents(string: "vcpgo://")!
urlComps.queryItems = queryItems
openURL(urlComps.url!)
}
fileprivate func createSharedFileUrl(_ url: URL?) -> String {
let fileManager = FileManager.default
let copyFileUrl =
fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.vcpgo")!
.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! + "/" + url!
.lastPathComponent.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
try? Data(contentsOf: url!).write(to: URL(string: copyFileUrl)!)
return copyFileUrl
}
func saveScreenshot(_ image: UIImage) -> String {
let fileManager = FileManager.default
let copyFileUrl =
fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.vcpgo")!
.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
+ "/screenshot.png"
do {
try image.pngData()?.write(to: URL(string: copyFileUrl)!)
return copyFileUrl
} catch {
print(error.localizedDescription)
return ""
}
}
fileprivate func handleTypeUrl(_ attachment: NSItemProvider)
async throws -> ShareItem
{
let results = try await attachment.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil)
let url = results as! URL?
let shareItem: ShareItem = ShareItem()
if url!.isFileURL {
shareItem.title = url!.lastPathComponent
shareItem.type = "application/" + url!.pathExtension.lowercased()
shareItem.url = createSharedFileUrl(url)
} else {
shareItem.title = url!.absoluteString
shareItem.url = url!.absoluteString
shareItem.type = "text/plain"
}
return shareItem
}
fileprivate func handleTypeText(_ attachment: NSItemProvider)
async throws -> ShareItem
{
let results = try await attachment.loadItem(forTypeIdentifier: kUTTypeText as String, options: nil)
let shareItem: ShareItem = ShareItem()
let text = results as! String
shareItem.title = text
shareItem.type = "text/plain"
return shareItem
}
fileprivate func handleTypeMovie(_ attachment: NSItemProvider)
async throws -> ShareItem
{
let results = try await attachment.loadItem(forTypeIdentifier: kUTTypeMovie as String, options: nil)
let shareItem: ShareItem = ShareItem()
let url = results as! URL?
shareItem.title = url!.lastPathComponent
shareItem.type = "video/" + url!.pathExtension.lowercased()
shareItem.url = createSharedFileUrl(url)
return shareItem
}
fileprivate func handleTypeImage(_ attachment: NSItemProvider)
async throws -> ShareItem
{
let data = try await attachment.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil)
let shareItem: ShareItem = ShareItem()
switch data {
case let image as UIImage:
shareItem.title = "screenshot"
shareItem.type = "image/png"
shareItem.url = self.saveScreenshot(image)
case let url as URL:
shareItem.title = url.lastPathComponent
shareItem.type = "image/" + url.pathExtension.lowercased()
shareItem.url = self.createSharedFileUrl(url)
default:
print("Unexpected image data:", type(of: data))
}
return shareItem
}
override public func viewDidLoad() {
super.viewDidLoad()
shareItems.removeAll()
let extensionItem = extensionContext?.inputItems[0] as! NSExtensionItem
Task {
try await withThrowingTaskGroup(
of: ShareItem.self,
body: { taskGroup in
for attachment in extensionItem.attachments! {
if attachment.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
taskGroup.addTask {
return try await self.handleTypeUrl(attachment)
}
} else if attachment.hasItemConformingToTypeIdentifier(kUTTypeText as String) {
taskGroup.addTask {
return try await self.handleTypeText(attachment)
}
} else if attachment.hasItemConformingToTypeIdentifier(kUTTypeMovie as String) {
taskGroup.addTask {
return try await self.handleTypeMovie(attachment)
}
} else if attachment.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
taskGroup.addTask {
return try await self.handleTypeImage(attachment)
}
}
}
for try await item in taskGroup {
self.shareItems.append(item)
}
})
self.sendData()
}
}
@objc func openURL(_ url: URL) -> Bool {
var responder: UIResponder? = self
while responder != nil {
if let application = responder as? UIApplication {
return application.perform(#selector(openURL(_:)), with: url) != nil
}
responder = responder?.next
}
return false
}
} ` Dump from AppDelegate.swift shows following data. Even if Im sharing 5 different files, in the dump you can see one exact file 5 times instead of 5 different files.
`5 elements ▿ 4 key/value pairs ▿ (2 elements)
thanks
Hello! Is this only on Whatsapp? Have you tried debugging ShareViewController.swift to see if the data arrives correctly at the plugin? (If not, I will test it later but I will have to set up a case first) Best regards
@carsten-klaffke Hi, it only happens when I share from WhatsApp, sharing multiple files from gallery works great. I tried to debug ShareViewController but I was not able to come to anything. ThankYou very much.
@tarangshah19 @carsten-klaffke Guys, any update on this issue please?
I created an Example (uploaded it to this repository) to test multiple file share. But I only have an iPad (no iPhone) and Whatsapp is not available for that. If you'd find another app where this happens, I could test it. Otherwise I have to wait to get an iPhone borrowed.
@carsten-klaffke same thing happens when you share from Telegram or Signal messaging app, can you please test it in one of those apps, they might be available for iPad, ThankYou!
Hey @StepZEROsk, I was now able to reproduce the bug (with Signal). There was an error in ShareViewController.swift, which put the same name for all images if they come as type image and not URL. I fixed it in the Code of SendIntentExample and also updated the Readme accordingly. Please let me know if this solves it for you!
@carsten-klaffke it works with Signal and Telegram, but still doesn't work with WhatsApp. Im not sure what the different is, but when I share from WhatsApp i'm getting the actual file name, not the name generated with the index, like Im getting from Signal and Telegram.
@carsten-klaffke From WhatsApp they comes like URL
Describe the bug Sharing works correctly when I select multiple photos from image gallery and share them to app. But when I receive photos in message using WhatsApp app, I select them in WhatsApp and share them to my app. I receive the intent with first photo multiple times.
To Reproduce Steps to reproduce the behavior:
Expected behavior Receive intent with multiple photos
Screenshots If applicable, add screenshots to help explain your problem.
Smartphone (please complete the following information):
Additional context
Data received from plugin:
[log] - intent {"type":"application%2Fjpg","url":"file%3A%2F%2F%2Fprivate%2Fvar%2Fmobile%2FContainers%2FShared%2FAppGroup%2FAF4D217D-A918-4245-9C60-ACDF619D2EBC%2F%2FPHOTO-2023-03-24-09-49-39.jpg","additionalItems":[{"url":"file%3A%2F%2F%2Fprivate%2Fvar%2Fmobile%2FContainers%2FShared%2FAppGroup%2FAF4D217D-A918-4245-9C60-ACDF619D2EBC%2F%2FPHOTO-2023-03-24-09-49-39.jpg","type":"application%2Fjpg","description":"","title":"PHOTO-2023-03-24-09-49-39.jpg"},{"url":"file%3A%2F%2F%2Fprivate%2Fvar%2Fmobile%2FContainers%2FShared%2FAppGroup%2FAF4D217D-A918-4245-9C60-ACDF619D2EBC%2F%2FPHOTO-2023-03-24-09-49-39.jpg","type":"application%2Fjpg","description":"","title":"PHOTO-2023-03-24-09-49-39.jpg"},{"title":"PHOTO-2023-03-24-09-49-39.jpg","description":"","url":"file%3A%2F%2F%2Fprivate%2Fvar%2Fmobile%2FContainers%2FShared%2FAppGroup%2FAF4D217D-A918-4245-9C60-ACDF619D2EBC%2F%2FPHOTO-2023-03-24-09-49-39.jpg","type":"application%2Fjpg"},{"title":"PHOTO-2023-03-24-09-49-39.jpg","description":"","url":"file%3A%2F%2F%2Fprivate%2Fvar%2Fmobile%2FContainers%2FShared%2FAppGroup%2FAF4D217D-A918-4245-9C60-ACDF619D2EBC%2F%2FPHOTO-2023-03-24-09-49-39.jpg","type":"application%2Fjpg"}],"description":"","title":"PHOTO-2023-03-24-09-49-39.jpg"}