Open Attachment from Mail Using iOS 8 App [Swift]

Open attachment from mail using ios 8 app [swift]

First of all you need to declare the file type your app will handle in your apps Info.plist.

For instance the configuration shown below declares that the app is able to open .lumenconfig files which are basically XML. See this for more info about the declarations.

<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<!-- The name of this file type. -->
<string>Lumen Configuration</string>
<key>CFBundleTypeIconFiles</key>
<!-- The name of this file type. -->
<array/>
<key>LSItemContentTypes</key>
<!-- The different type identifiers that are handled
as this type of file. -->
<array>
<!-- This is a custom type I declare below -->
<string>at.zujab.lumen.lumenconfig</string>
</array>
</dict>
</array>

If you use a custom type like I do in the above example you also need to declare that type. See this for more information about declaring your own type

<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<!-- How these files are structured -->
<array>
<string>public.xml</string>
</array>
<key>UTTypeIdentifier</key>
<!-- This is the identifier for the custom type -->
<string>at.zujab.lumen.lumenconfig</string>
<key>UTTypeDescription</key>
<!-- How your app calls these files. -->
<string>Lumen Configuration File</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<!-- The extension of the files of this type -->
<string>lumenconfig</string>
</dict>
</dict>
</array>

Then in your app delegate implement a handler to handle the file:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

//....

func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) -> Bool {
//url contains a URL to the file your app shall open

//In my EXAMPLE I would want to read the file as a dictionary
let dictionary = NSDictionary(contentsOfURL: url)

}

}

Open any email attachment inside the ios app

Actually my requirement is from my app I will go to the mail box. If any attachment present there, I have to open it with my app. Not only I want to open it with my app, but also I want to save the file in my documents directory.

You can't tell the Mail app what to do so what you want is not exactly possible.

What you can do is add your app in the "Open In" menu by supporting some file types. So that when the user taps the attachment your app will appear in the list of apps.

You can do that this way:

  1. Add the file types your app can handle. Follow the instructions here: https://developer.apple.com/library/archive/qa/qa1587/_index.html

  2. Once 1. is done add the following function in your AppDelegate:

func application(application: UIApplication, handleOpenURL url: NSURL) -> Bool {
// do what you want with file
}

To save the file in your app's document directory you can see how it's done here:
https://programmingwithswift.com/save-file-to-documents-directory-with-swift/

iOS Custom attachment not opening directly from Messages

Update: This is how opening a custom attachment now works in iOS 15.6.

Touch the profile icon for the conversation. This either a picture or initials at the top of the screen. Scroll down to the attachments section. Open the attachment from there.

Sample Image

Handling files opened from outside sources in iOS/Swift

The only part that matters is this part:

// Add at end of application:didFinishLaunchingWithOptions
NSURL *url = (NSURL *)[launchOptions valueForKey:UIApplicationLaunchOptionsURLKey];
if (url != nil && [url isFileURL]) {
[rootController handleOpenURL:url];
}

// Add new method
-(BOOL) application:(UIApplication *)application handleOpenURL:(NSURL *)url {

RootViewController *rootController = (RootViewController *) [navigationController.viewControllers objectAtIndex:0];
if (url != nil && [url isFileURL]) {
[rootController handleOpenURL:url];
}
return YES;

}

The first code block is added to your AppDelegate's application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?)

The Swift equivalent is

if let options = launchOptions, let url = options[.url] as? URL, url.isFileURL {
// call some code to handle the URL
}

and this new function for the AppDelegate:

func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if url.isFileURL {
// call some code to handle the URL
}
return true // if successful
}

All of the rest of the code in the article is a way to route the handling code to the root view controller. You could just handle it right in the AppDelegate or route it to another class if you wish.

Share attachment from Mail App with Share extension in iOS

So finally I found an answer on my question! Just in case if somebody will meet the same problem..
First of all I have to use PREDICATE statement (Subquery) in Info.plist instead of key NSExtensionActivationSupportsAttachmentsWithMaxCount. Like:

        <key>NSExtensionActivationRule</key>
<string>SUBQUERY (
extensionItems,
$extensionItem,
SUBQUERY (
$extensionItem.attachments,
$attachment,
(
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "com.adobe.pdf"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.image"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.plain-text"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.png"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.jpeg"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.jpeg-2000"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.tiff"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "com.compuserve.gif"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "com.microsoft.bmp"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "com.microsoft.word.doc"
)
).@count == 1 // Important! to activate extension only on 1 chosen image
).@count == 1
</string>

Second: Properly get all attachments using necessary TypeIdentifier (UTI):

    if let content = extensionContext!.inputItems.first as? NSExtensionItem {
if let contents = content.attachments as? [NSItemProvider] {
for attachment in contents{
attachment.loadItemForTypeIdentifier("public.item", options: nil) { data, error in
let url = data as! NSURL
let fileExtension = url.pathExtension as String!
let fileName = self.generateImageName() as String
if let fileData = NSData(contentsOfURL: url) {
self.uploadFile("\(fileName).\(fileExtension)", data: fileData)
}
}
}
}
}

"public.item" - is universal UTI to support all kind of file extensions listed in your NSExtensionActivationRule string.
You can get necessary UTI on https://developer.apple.com

Good Luck with developing of action extensions! Any questions are welcome!

Launch Apple Mail App from within my own App?

Apparently Mail application supports 2nd url scheme - message:// which ( I suppose) allows to open specific message if it was fetched by the application. If you do not provide message url it will just open mail application:

NSURL* mailURL = [NSURL URLWithString:@"message://"];
if ([[UIApplication sharedApplication] canOpenURL:mailURL]) {
[[UIApplication sharedApplication] openURL:mailURL];
}


Related Topics



Leave a reply



Submit