- Home /
iOS open docx file from Application.persistentData
I have written a mobile unity app that needs to open a downloaded docx file. I can do this on my android build by simply calling Application.OpenUrl(myPath); and it works fine.
I found that it is not so simple in iOS. I have written a small plugin to use the native iOS code to launch the files. At first the code would crash the app when i would click the button that calls the plugin. But I "fixed" the issue that was causing the crash but now nothing is happening when I call the plugin to launch the file.
The logic steps didn't change just the methods and arguments used.
This is the unity class for launching the file:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
public static class FileLauncher {
#if UNITY_IOS
[DllImport ("__Internal")]
private static extern bool _canOpenURL(string _url);
[DllImport ("__Internal")]
private static extern void _openURL(string _url);
#endif
public static void LaunchFile(string _path){
#if UNITY_IOS
try{
if(Application.platform == RuntimePlatform.IPhonePlayer){
if(CanOpenURL(_path)){
_openURL(_path);
}
else{
Debug.Log("FILELAUNCHER: canopen false");
}
}
}
catch(Exception _err){
Debug.Log("FILELAUNCHER: " + _err.Message);
}
#else
Application.OpenURL(_path);
#endif
}
public static bool CanOpenURL(string _path){
#if UNITY_IOS
try{
if(Application.platform == RuntimePlatform.IPhonePlayer){
return _canOpenURL(_path);
}
}
catch(Exception _err){
Debug.Log("FILELAUNCHER: " + _err.Message);
return false;
}
#endif
return true;
}
}
And this is the current plugin I have written:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface SampleClass : NSObject
-(bool)CanOpenURL:(NSString *)_url;
-(void)OpenURL:(NSString *)_url;
@end
@implementation SampleClass
-(bool)CanOpenURL:(NSString *)_url{
UnitySendMessage("AppController", "iOSLog", "CanOpenURL");
if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:_url]]){
return YES;
}
return NO;
}
-(void)OpenURL:(NSString *)_url{
UnitySendMessage("AppController", "iOSLog", "OpenURL");
NSURL *url = [[NSBundle mainBundle] URLForResource:_url withExtension:@"docx"];
if(url){
UIDocumentInteractionController *docController = [UIDocumentInteractionController interactionControllerWithURL:url];
UIViewController *viewController = [[[[UIApplication sharedApplication]delegate]window]rootViewController];
[docController presentOpenInMenuFromRect:CGRectZero inView:viewController.view animated:YES];
}
else{
UnitySendMessage("AppController", "iOSLog", "OpenFailed");
}
}
@end
extern "C"
{
bool _canOpenURL(NSString* _url){
SampleClass *test = [[SampleClass alloc] init];
return [test CanOpenURL:_url];
}
void _openURL(NSString* _url){
SampleClass *test = [[SampleClass alloc] init];
[test OpenURL:_url];
}
char* cStringCopy(const char* _string){
if (_string == NULL){
return NULL;
}
char* res = (char*)malloc(strlen(_string) + 1);
strcpy(res, _string);
return res;
}
}
I do not have a background in iOS so I am thinking i am overlooking a step or something simple in the interaction between iOS and unity that someone on here may see immediately.
Thanks for your help!
Hi @wolftamer389! I'm looking to do exactly this and I'm wondering if you managed to find a good solution? If so, would you $$anonymous$$d sharing it? I would be extremely grateful! Thanks a lot
I am not sure what type of file you are trying to load but I ended up using the Prime31 package called Etcetera. It allows me to launch a WebView with the document the way I wanted.
Thanks!! I came across that plugin while I was searching for solutions and it definitely looks like a good option if you're going to use the functionality often.
I actually got the plugin working, your code helped me a lot getting started so thanks for sharing! I believe what's happening with your code is that you're not specifying the right UIViewController. If you're interested in giving it another try I will more than happy share my code.
Answer by martejpad · Oct 27, 2017 at 02:34 PM
Hi everyone,
I thought I'd share a working plugin that opens a document within an iOS app, as @wolftamer389 was attempting. The document path is specified from a Unity script. Please bare in mind that this is my first time writing Objective-C code and dealing iOS plugins!
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface DocumentHandler : NSObject <UIDocumentInteractionControllerDelegate>
{
NSURL * fileURL;
}
- (id)initWithURL:(NSURL*)unityURL;
- (void)UpdateURL:(NSURL*)unityURL;
- (bool)OpenDocument;
- (UIViewController *) documentInteractionControllerViewControllerForPreview: (UIDocumentInteractionController *) controller;
@end
@implementation DocumentHandler
- (id)initWithURL:(NSURL*)unityURL
{
self = [super init];
fileURL = unityURL;
return self;
}
- (void)UpdateURL:(NSURL*)unityURL {
fileURL = unityURL;
}
- (bool)OpenDocument {
UIDocumentInteractionController *interactionController =
[UIDocumentInteractionController interactionControllerWithURL: fileURL];
// Configure Document Interaction Controller
[interactionController setDelegate:self];
[interactionController presentPreviewAnimated:YES];
return true;
}
- (UIViewController *) documentInteractionControllerViewControllerForPreview: (UIDocumentInteractionController *) controller {
return UnityGetGLViewController();
}
@end
static DocumentHandler* docHandler = nil;
// Converts C style string to NSString
NSString* CreateNSString (const char* string)
{
if (string)
return [NSString stringWithUTF8String: string];
else
return [NSString stringWithUTF8String: ""];
}
extern "C" {
bool OpenDocumentOnIOS (const char* path)
{
// Convert path to URL
NSString * stringPath = CreateNSString(path);
NSURL *unityURL = [NSURL fileURLWithPath:stringPath];
if (docHandler == nil)
docHandler = [[DocumentHandler alloc] initWithURL:unityURL];
else
[docHandler UpdateURL:unityURL];
[docHandler OpenDocument];
return true;
}
}
Simply add this file as a .mm in your Classes folder inside the Xcode project exported by Unity. Finally, to call this function from a Unity script, do the following:
#if UNITY_IOS
[DllImport ("__Internal")]
internal static extern bool OpenDocumentOnIOS (string path);
#endif
And then call your the function normally.
I really hope this helps!
@martejpad - What did you name the .mm file as when you put it in the XCode 'Classes' folder? I am having issues getting you code to work. Help is greatly appreciated.
Hi @lanrosta, really sorry for the delay. I didn't name my file anything special, just OpenDocument.mm. What are you having trouble with? Hope you've managed to solve your issue :)
This is amazing, thanks! I got it working on my app. It launches the document on iOS, without losing context of the app as well. Great!
@martejpad Thanks for providing this it's extremely helpful when I know very little about writing iOS plugins. I'm trying to convert this to make it work with pdfs stored remotely at a https url is there any help you can give me? I feel like it probably only needs a small change but I'm struggling to figure it out as the viewer opens but there's nothing displayed. this is the error I'm getting in xcode
$$anonymous$$YAPP[333:37903] [default] QLUbiquitousItemFetcher: could not create sandbox wrapper. Error: Error Domain=NSPOSIXErrorDomain Code=2 "couldn't issue sandbox extension com.apple.quicklook.readonly for '/https:/$$anonymous$$YAPP.com/assets/resources/$$anonymous$$YPDF.pdf': No such file or directory" UserInfo={NSDescription=couldn't issue sandbox extension com.apple.quicklook.readonly for '/https:/$$anonymous$$YAPP.com/assets/resources/$$anonymous$$YPDF.pdf': No such file or directory} #PreviewItem
Answer by Pascal- · Dec 07, 2018 at 11:53 AM
Hello @martejpad,
Sorry, I'm new with IOS. I'd like to know how to open a pdf stored in the steaming assets folder in a pdf reader app using your plugin. How to do so with a unity script? It's pretty simple on Android, but with IOS it seams more difficult.
Thanks a lot for your help, Pascal