I am trying to get the imageURL the ios share extension uses for the thumbnail generated in the action sheet.
I am retrieving the URL fine but cannot seem to figure out how to get the imageURL.
Here is how I get the normal URL,
if let item = extensionContext?.inputItems.first as? NSExtensionItem {
if let itemProvider = item.attachments?.first as? NSItemProvider {
if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeItem as String) {
itemProvider.loadItem(forTypeIdentifier: kUTTypeItem as String, options: nil, completionHandler: { (url, error) -> Void in
if let shareURL = url as? NSURL {
let components = URLComponents(url:shareURL as URL, resolvingAgainstBaseURL: true)
if let host = components?.host { self.shareTitle = host }
self.shareURL = shareURL.absoluteString!
self.POSTShareData(completion: nil)
}
self.extensionContext?.completeRequest(returningItems: [], completionHandler:nil)
})
}
}
}
I have tried to changing the typeIdentifier to kUTTypeImage to no avail. I have my info.plist set to NSExtensionActivationRule to TRUEPREDICATE to see what I can retrieve. I am thinking maybe I have to be more explicit in the .plist ??
I am targeting iOS 9.3
A workaround is that you can store that URL link in common UserDefaults
eg:- let defaults = UserDefaults(suiteName: "group.com.common.Notification")
Then access it in-app or extension
Related
I am looking for either a Swift or Objective C solution for this. Here, I am showing my example using swift.
I am using the Photos framework on iOS and having a hard time finding the REAL filename instead of the IMG_4227.JPG type. The name of my image is actually myawesomefilename.jpg and I see this file name if I airdrop or transfer to dropbox the image from my iPhone. But when I use the Photos framework, I get the names as IMG_4227.JPG.
There is an app on the app store which is able to get the real file names of all images, so it is definitely possible. I just don't know how.
Here's how I am currently getting the IMG_4227.JPG type names:
func exifTapped(asset: PHAsset) {
print("name: \(asset.value(forKey: "filename"))")
getURL(ofPhotoWith: asset) { (url) in
print("URL: \(url)")
let data = NSData.init(contentsOf: url!)!
if let imageSource = CGImageSourceCreateWithData(data, nil) {
let imageProperties2 = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil)! as NSDictionary
print("imageProperties2: ", imageProperties2)
}
}
}
func getURL(ofPhotoWith mPhasset: PHAsset, completionHandler : #escaping ((_ responseURL : URL?) -> Void)) {
if mPhasset.mediaType == .image {
let options: PHContentEditingInputRequestOptions = PHContentEditingInputRequestOptions()
options.isNetworkAccessAllowed = true
options.canHandleAdjustmentData = {(adjustmeta: PHAdjustmentData) -> Bool in
return true
}
mPhasset.requestContentEditingInput(with: options, completionHandler: { (contentEditingInput, info) in
completionHandler(contentEditingInput!.fullSizeImageURL)
})
} else if mPhasset.mediaType == .video {
let options: PHVideoRequestOptions = PHVideoRequestOptions()
options.version = .original
options.isNetworkAccessAllowed = true
PHImageManager.default().requestAVAsset(forVideo: mPhasset, options: options, resultHandler: { (asset, audioMix, info) in
if let urlAsset = asset as? AVURLAsset {
let localVideoUrl = urlAsset.url
completionHandler(localVideoUrl)
} else {
completionHandler(nil)
}
})
}
}
EDIT: None of the duplicate solutions are any different than what I already have and they all give the IMG_4227.JPG type names instead of the real name. So this is not a duplicate.
I figured it out.
let resources = PHAssetResource.assetResources(for: asset)
print("Filename: \((resources.first as! PHAssetResource).originalFilename)")
I see different behavior on iOS 11 vs 12.
On iOS 11 - I get the filepath of files shared in completion handler.
On iOS 12 - I get a URL domain error. But if i handle it based on the type (eg: UIImage), then I get the file content.
Is this behaviour only on simulator or on device as well ?
Do we need to handle this per iOS version ?
Yes you will get both thing (file path or data) on device also. You did not need to add any check on iOS version.
Please flow my code. It is in swift but you can understand it.
func share() {
let inputItem = extensionContext!.inputItems.first! as! NSExtensionItem
let attachment = inputItem.attachments!.first as! NSItemProvider
if attachment.hasItemConformingToTypeIdentifier( kUTTypeImage as String) {
attachment.loadItem(forTypeIdentifier: kUTTypeImage as String, options: [:]) { (data, error) in
var image: UIImage?
if let someURl = data as? URL {
image = UIImage(contentsOfFile: someURl.path)
}else if let someImage = data as? UIImage {
image = someImage
}
if let someImage = image {
guard let compressedImagePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first?.appendingPathComponent("shareImage.jpg", isDirectory: false) else {
return
}
let compressedImageData = UIImageJPEGRepresentation(someImage, 1)
guard (try? compressedImageData?.write(to: compressedImagePath)) != nil else {
return
}
}else{
print("bad share data")
}
}
}
}
Before iOS 11 came out I created a share extension to my social media app. It worked perfectly fine. Once iOS 11 came out, the share extension quit working. I searched and debugged the extension until I found the source of the problem. When looping through the attachments inside the extensionContext.inputItems[0].attachments, none of the attachments has an item conforming to kUTTypeImage. So none of my code was running from that point on. I also had another strange outcome yesterday. This is part of my code inside the didSelectPost function.
guard let content = extensionContext?.inputItems[0] as? NSExtensionItem else { return }
guard let contentAttachments = content.attachments as? [NSItemProvider] else { return }
let skyName = self.textView.text
for attachment in contentAttachments {
if attachment.hasItemConformingToTypeIdentifier(imageType) {
attachment.loadItem(forTypeIdentifier: imageType, options: nil) { (data, error) in
guard error == nil, let url = data as? NSURL else { return }
self.imageFromAsset(url: url as URL)
if !self.selectedType.isEmpty {
do {
let imageData = try Data(contentsOf: url as URL)
self.skyImage = UIImage(data: imageData)
self.saveSkyImage()
guard let skyOriginalImageURL = self.skyOriginalImageURL else { return }
guard let skyImageURL = self.skyImageURL else { return }
let newSky = Sky(name: skyName ?? "Another Sky",
type: self.selectedType,
date: self.date,
location: self.location,
picture: CKAsset(fileURL: skyImageURL),
likes: 0, flags: 0,
likedBy: [CKReference](), flaggedBy: [CKReference](),
originalImage: CKReference(record: CKRecord(recordType: "SkyImage"), action: .none))
let newSkyImage = SkyImageFullResolution(picture: CKAsset(fileURL: skyOriginalImageURL))
self.saveSky(sky: newSky, skyImage: newSkyImage)
} catch {
print(error.localizedDescription)
self.closePostWindow()
}
}
}
}
}
defer {
closePostWindow()
}
I don't have a direct answer to your problem but recently in iOS 11 I have resolved a problem to display a share extension involving PDF files.
My problem was that my expected type identifiers were not found among the attachments.
NSItemProvider has an instance property registeredTypeIdentifiers to show you the type identifiers that can be found when your extension is activated.
That's what I do :
1) I use TRUEPREDICATE as NSExtensionActivationRule to force display my share extension in the context of my interest.
2) After you select your share extension, your extension code will be triggered.
Then you print all the type registeredTypeIdentifiers of each attachment, by looping through your contentAttachments.
Once you have identified all the identifiers, you will be able to find a solution to your problem.
I'm implementing a share extension that sends images to a server for computation.
In addition to my progress bar issues, I'm not able to use the images from Twitter app. Here is the code I'm using which is working in many other third party apps.
if let inputItem = extensionContext!.inputItems.first as? NSExtensionItem {
if let itemProvider = inputItem.attachments?.first as? NSItemProvider {
if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
itemProvider.loadItem(forTypeIdentifier: kUTTypeImage as String) { [unowned self] (imageData, error) in
let url = imageData as! URL
self.sendToServer(localUrl: url)
}
}
}
}
The error I have is the following: Could not cast value of type 'NSConcreteData' (0x1a8d45700) to 'NSURL' (0x1a8d36a10) and occurs for this part of the code let url = imageData as! URL.
It seems that the item is of type image. Any idea why that is happening while it works for the other apps?
Thanks for your help.
I managed to fix that by using the following code, which takes into account different ways the photo is passed by the itemProvider.
itemProvider.loadItem(forTypeIdentifier: kUTTypeImage as String){ [unowned self] (data, error) in
let myImage: UIImage?
switch data {
case let image as UIImage:
myImage = image
case let data as Data:
myImage = UIImage(data: data)
case let url as URL:
let imageData = NSData(contentsOf: url.absoluteURL)
myImage = UIImage(data: imageData! as Data)
default:
//There may be other cases...
print("Unexpected data:", type(of: data))
myImage = nil
}
self.sendToServer(imageData: myImage!, imageName: myImageName)
}
Hi viewer I have a problem with my Action Extension for iOS where I'm trying to get the Public URL that Safari has opened currently but i can't tell if i have the Public URL since its not showing in the Debugger. Matter of Fact the Debugger is Black and the only information that shows is if the Action Extension gets interrupted/ crashes.
Heres my code that gets the Public.url from safari.
//get the itemProvider which wraps the url we need
var item : NSExtensionItem = self.extensionContext!.inputItems[0] as! NSExtensionItem
var itemProvider : NSItemProvider = extensionItem.attachments?.first as! NSItemProvider
//pull the URL out
if (itemProvider.hasItemConformingToTypeIdentifier("public.url")) {
itemProvider.loadItemForTypeIdentifier("public.url", options: nil, completionHandler: { (urlItem, error) in
let url : NSURL = urlItem as! NSURL
//do what you need to do now, such as send a request to your server with this url
println(url.absoluteString!);
})
}
Is there a better way of doing it its written in swift and Plus I've look around and couldn't find a better solution so I'm asking is there a tutorial or an example I can follow.
I believe the following would work:
let item : NSExtensionItem = self.extensionContext!.inputItems[0] as! NSExtensionItem
let itemProvider : NSItemProvider = item.attachments?.first as! NSItemProvider
//pull the URL out
if (itemProvider.hasItemConformingToTypeIdentifier("public.url")) {
itemProvider.loadItemForTypeIdentifier("public.url", options: nil, completionHandler: { (urlItem, error) in
let url : NSURL = urlItem as! NSURL
//do what you need to do now, such as send a request to your server with this url
print(url.absoluteString);
})
}