KasemJaffer / receive_sharing_intent

A Flutter plugin that enables flutter apps to receive sharing photos, text and url from other apps.
Apache License 2.0
333 stars 391 forks source link

Sharing from iOS' "instant markup" doesn't do anything #64

Open geoah opened 4 years ago

geoah commented 4 years ago

There seems to be an issue when sharing images from some apps, mainly from "instant markup".

To replicate this, take a screenshot, and once the screenshot pops up on the bottom left, click on it to show the "instant markup" tool. If you now draw something on the picture, hit "share", and select the app that uses "receive_sharing_intent", nothing will happen.

From what I can tell, in this case, iOS doesn't send a URL for the image, but the data itself. I think the problem and solution is something close to this discussion.

I tried to get the image data and store them in a file instead of copying them from the URL, but I couldn't get it to work as I don't really do swift and suck at it.

Has anyone else ever bumped into the issue? If so, I'd really appreciate if you could share your handlers for images. :)

Thank you!

daniilsv commented 3 years ago

bump have same issue now, dont know how to solve except rewriting native ios lib

gicha commented 3 years ago

I solved this problem. @geoah Thanks for the link on StackOverflow, it helped. That happened cause the instant markup was sending the UIImage instead of url of file

To fix it, add the following code to the "ios / Share Extension / ShareViewController.swift" file

This line in the place of declaring constants

let uiImageContentType = kUTTypeData as String

Add this method

private func handleUIImages (content: NSExtensionItem, attachment: NSItemProvider, index: Int) {
        attachment.loadItem(forTypeIdentifier: uiImageContentType, options: nil) { [weak self] data, error in
            if error == nil, let imageData = data as? UIImage, let this = self {
                DispatchQueue.main.async {
                    let newName = UUID().uuidString
                    let newPath = FileManager.default
                        .containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")!
                        .appendingPathComponent("\(newName).png")
                    let copied = this.createFile(image: imageData, srcURL: newPath)
                    if(copied) {
                        this.sharedMedia.append(SharedMediaFile(path: newPath.absoluteString, thumbnail: nil, duration: nil, type: .image))
                    }
                    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)
                    }
                }
            }
        }
    }

And this condition to viewDidLoad() method

if attachment.hasItemConformingToTypeIdentifier(uiImageContentType) {
                        handleUIImages(content: content, attachment: attachment, index: index)
  }
MagTuxGit commented 3 years ago

@gicha Not a good solution. It fails text data to be handled.

It's better idea to check data type inside handleImages method.

                let fileExtension: String = {
                    if let url = data as? URL {
                        return this.getExtension(from: url, type: .image)
                    }
                    if data is UIImage {
                        return "png"
                    }
                    return ""
                }()

                let newName = UUID().uuidString
                let newPath = FileManager.default
                    .containerURL(forSecurityApplicationGroupIdentifier: "group.\(this.hostAppBundleIdentifier)")!
                    .appendingPathComponent("\(newName).\(fileExtension)")

                var copied = false
                if let url = data as? URL {
                    copied = this.copyFile(at: url, to: newPath)
                }
                if let image = data as? UIImage, let imageData = image.pngData() {
                    do {
                        try imageData.write(to: newPath)
                        copied = true
                    } catch {}
                }
                if copied {
                    this.sharedMedia.append(SharedMediaFile(path: newPath.absoluteString, thumbnail: nil, duration: nil, type: .image))
                }