how app extension can access the containing app images/assets/resource data - ios8

I implemented the document provider app extension feature with my own
ios app. The problem is the app extension was not able to access the
containing app images/assets or the containing apps resource data.
Does any one knows how to achieve it?.

The extension has its own target in your Xcode project. In order to access resources in the extension you also need to add them to that target (in the File Inspector also check your extension target in the Target Membership section). Just be aware that those resources also get copied into the extension bundle, which increases your overall app size.
Sidenote: In my extension I didn't add my default image asset catalogue (Images.xcassets) to the extension, but was still able to access the containing images. Maybe that's an exception.

UPDATE
If you are supporting iOS 8 and up, you can create a framework to share among your app and it's extensions, and embed resources, strings, etc. inside of it. Make sure to use the [UIImage imageNamed:inBundle:compatibleWithTraitCollection:] and NSLocalizedStringFromTableInBundle methods, passing in the bundle that is your framework.
PREVIOUS ANSWER
Given that extensions are (and hopefully always will be) in a sub-folder of the main app at /Plugins/PluginName and have permissions to access files just like the main app, you can do the following (and I do in some of my apps on the store):
// image
UIImage* image = [UIImage imageNamed:#"../../image_name.png"]
// data
NSString* path = [NSHomeDirectory() stringByAppendingPathComponent:#"../../file.json"];
NSData* data = [NSData dataWithContentsOfFile:path];
This will save you a lot of space, especially if your extension uses a lot of images.

Related

Cocoa Mac OS X application bundling 1000 images

We have a Cocoa Mac OS X application in which we want to bundle around 500 images. Each image is around 10kb so size isn't a problem.
These images are not exactly resources in the app, they are sample images.
Basically, we have simple button that would let the user copy these images to a directory.
The solution also needs to be "dump in, dump out" -- so we don't want to store individual image file names somewhere in our application; we just want to have a directory of images that can be copied.
How do I package these into my application?
The question turns into: How do I make a directory resource containing the images.
In our case everything gets flattened into the MyApp.app/Contents/Resources and this approach would require us to put image names in the app so that we can copy those.
Put the images into a folder. Drag the folder into your project in Xcode. In the resulting dialog, make sure you copy, make sure you create a folder reference, and make sure you add to your app target. Done. Now the folder is part of your app bundle and you can refer to it from your code without knowing anything about its contents.
The folder /Library/Application Support is for support files that, if deleted, would not affect the execution of an application. I would suggest this is ideal for your product's sample images.
As Apple's documentation states for Application Support:
Use this directory to store all app data files except those associated with the user’s documents. For example, you might use this directory to store app-created data files, configuration files, templates, or other fixed or modifiable resources that are managed by the app. An app might use this directory to store a modifiable copy of resources contained initially in the app’s bundle.
So, use pkgbuild / productbuild to install them to /Library/Application Support/<ProductName>/
Because size is not an issue, you can just put all your sample images in separate Asset Catalog file.

Adding a .xcassets file to an Xcode framework project

I've got a framework project that uses a number of images. As it stands I just drag these images into the project so that they sit alongside my source files:
When I embed this project into a separate app project, I can access these resources as expected.
Ideally, I'd now like to organize my framework images with a .xcassets file. Unlike app projects, the framework project template doesn't provide one of these by default, so I've added one manually using the File > New menu. Unfortunately when I rebuild the framework and re-embed it, I can no longer access the images. Is what I'm trying to do possible?
If you want to access assets in a subproject (framework etc.) you need to make sure that you are collecting them from their own bundle since they are not part of the Main Bundle.
You can do that simply with this Swift 4 code:
let bundle = Bundle(for: type(of: self))
let image = UIImage(named: "imageName", in: bundle, compatibleWith: nil)
From what I can make out, the answer to my question is yes, sort of...
To make use of the NSImage(named: ...) API one of two things needs to be true: either the image should exist within the app's main bundle, or (to paraphrase the docs):
[there should be] an [NSImage] object whose name was set explicitly using the setName: method and currently resides in the image cache.
In the case where the image resides in an embedded framework, the first isn't true since the framework is a separate bundle, and there's no way of adding to the main bundle at runtime. This leaves the second approach.
Whenever your code is going to use NSImage(named: ...) make sure you've already loaded the image using some other way, then set its name:
let bundle = NSBundle(forClass: MyFrameworkClass.self)
let image = bundle.imageForResource(name) // image in the framework .xcassets
image.setName(name)
I don't know how much use this is, and you should definitely be aware of the notes in the docs about how the image cache operates, but it is at least one way of storing images in a .xcassets folder in one bundle, then accessing them from another.

Display WebArchive from Mail.app and Notes.app

Cocoa's WebView can display .webarchive files. The ones I try to display come from the pasteboard, e.g. when copying parts of a web page in Safari or Mail.app.
The issue I am having is that webarchives from Mail and Notes won't display in a WebView, while webarchives from Safari do.
I looked inside the data of those archives (BBEdit can decypher their binary plist format and show it as XML nicely) and found that the issue is caused by the unusual URL references Mail (and Notes) puts in there:
<key>WebResourceURL</key>
<string>x-msg://4/</string>
If I remove that entry or change it to something using http://, WebView suddenly can display such archives.
Now, how do I solve this in general in my code?
I don't want to have to decode the webarchive, find the WebResourceURL entry and remove it before passing the archive to the WebFrame for loading.
I wonder if there's something else I have to set up with either the WebView or its main frame to make this work.
I noticed that Xcode can show these webarchives just fine, suggesting that Xcode uses WebKit in a more "proper" way that solves the issue. But then, maybe that's just because it has NSWebFrame load the archive from disk, while my code loads it from a CFData object - when loading from a file, WebKit may be using that file URL as the base URL, while it only chokes on it when it doesn't get a usable URL at all.
I have created a little demo project for Xcode here: http://files.tempel.org/Various/Mail-WebArchive-Display-Issue.zip
It includes both an original archive from Mail ("mail-bad.webarchive") and a fixed one ("mail-good.webarchive"), both of which are displayed in two webViews in the demo app.
I had also opened a Tech Support Indident (TSI) with Apple DTS, and the responded that I should file a bug. The bug report can be seen here: http://openradar.appspot.com/radar?id=2843403
After brooding over what Xcode might be doing I found a solution:
This does not work:
WebArchive *archive = [[WebArchive alloc] initWithData:webData];
[[webView mainFrame] loadArchive:archive];
But this does:
[[webView mainFrame] loadData:webData MIMEType:#"application/x-webarchive" textEncodingName:#"" baseURL:NULL];
So, the explicit function to load the archive is faulty while the one that wants an explicit URL, even though I give it none, works.
Go figure.

Cocoa WebView (MacApp) - how to use custom fonts?

I have a WebView in a Cocoa application (macgap).
(NOTE I'm not talking about a UIWebView in an iOS app)
In my CSS file, there are some custom font declarations:
#font-face{
font-family:'Quivira';
src:url("./Quivira.ttf") format("truetype");
font-weight:normal;
font-style:normal;
}
I can't get these to load however - some sort of security issue I believe.
Sometimes, I can see there is an error in the console "Not allowed to load local resource: Quivira.ttf" (it doesn't always show this though)
What could be causing this? The index.html file is loaded via the file:/// protocol so there shouldn't be a security issue, as it is already local and should therefor be able to load local resources.
I'm thinking it could be a bug in webkit.
Is anyone able to load custom fonts in a Cocoa WebView?
I have tried two approaches to load webpages with custom fonts.
From the app bundle (using NSBundle)
From a local path specified by the user (using absolute path)
In both cases I am successfully able to display Custom Fonts. There is a HTML file and beside it, a .ttf font file. In the HTML file I have defined #font-face in inline CSS.
In the second case you can give any full path from local filesystem and the webview will load from that (like /Users/johndoe/Desktop/maiwebsite/index.html).
Code is on Github.
And from another answer on SO:
Instead of getting the resource path and stapling a subpath onto it yourself, ask the bundle to give you the correct path.
Instead of handling a path at all, ask the bundle to give you the correct URL. (Requires Mac OS X 10.6 or later.)
If this doesn't help then could you put up your code somewhere so we can try to debug it?
For WKWebView (WebView now deprecated), load custom fonts from the MacApp bundle like so:
[_webView loadHTMLString:htmlContent baseURL:[[NSBundle mainBundle] resourceURL]];
Unlike iOS where all one needs to supply for bundle resources is: [[NSBundle mainBundle] bundlePath] (iOS Bundle is flatter), for MacApps the path to resources is more complex and bundlePath alone will NOT work. The above approach DOES work.
In your CSS simply use #font-face like so and any fonts in the location specified by resourceURL will be found.
#font-face {font-family:'myfont';src:url('myfont.ttf');}

Loading resources from folders contained in Resources folder.

I'm using cocos2d for a little IOS game I'm developing. I like to have my assets splitted in differnt directories like:
Levels/Level1/gfx
Levels/Level1/sounds
Levels/Level1/maps
etc...
So, I have created this directories inside the Resources one. The problem is that I'm unable to load anything if the asset is not inside Resources directory. I mean Resources/image.png will load but Resources/images/image.png won't.
As a cocos2d example, [sprite spriteFromFile:#"image.png"] will load but [sprite spriteFromFile:#"images/image.png"] won't.
As a side note I must say that I don't use groups, I fisically create the folders in the filesystem and then I add them to xcode.
Is there anything special I must do to load an assets that is not directly contained by Resources directory?.
Thanks in advance.
Since there is no link between the tree structure (groups, etc) diplayed in the Project Tree and the actual position of the files, you have to be carefull about how you move files around on your disk. You should put the files at their right place on your disk, THEN drop them on your project tree in XCode. After that you shouldn't move them again, otherwise Xcode will keep the old path to them, and the logical reference to the file is lost (in Xcode).
And be sure to uncheck the checkbox on the top so that Xcode will only create a reference to your files without copying them himself.
you could tried getting the file path manually from NSBundle:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"image" ofType:#"png" inDirectory:#"images"];
Now that you have the file path, im not sure how to set the image to the sprite.. Maybe you could try through CGImage...
Hope this helps

Resources