Adding a .xcassets file to an Xcode framework project - xcode

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.

Related

Image inside folder with two-letter name ('bg') disappears when packaged as UWP app

I've got a really weird problem building a Windows 10 UWP app. When I test on my device in both debug and release modes, an image I set as Background appears perfectly fine. It resizes, etc.
However, when I package the app in preparation for store deployment and install the package to test, images are showing as white.
Here's the code in question:
mainGrid.Background = new ImageBrush { ImageSource = new BitmapImage(new Uri(#"ms-appx:///Assets/bg/" + Config.bgImage + ".jpg")), Stretch = Stretch.UniformToFill };
What confuses me the most is why it works in debug/release, but only fails when its released as a package.
The image is set as "Content" and "Copy Always".
Any ideas?
Thanks in advance!
Per comment, this is due to a folder being named bg and the project being set to create a "bundle" (ie, a main package and then a separate package for each language).
For better or worse, the packaging system assumes that any directory with a 2-letter name is a language code (like "en" or "de") and therefore assumes the assets are specific to that language. Those assets are placed in a separate package that are only installed if applicable for the current user.
If you have a large number of assets, and you're localizing them, using a bundle is still a good approach to minimize the app size and download time, in which case you would need to change the directory name to something a bit longer (technically you can control the packaging yourself but it's a lot of work... renaming is probably easier).
But if you don't localize / aren't worried about bloating the app too much, then creating a single package is fine.

How to distribute Image folder?

I have a sandboxed osx app which contains a huge number of logos as png-files.
If there are any logos missing, the app downloads the missing logos automitcally from the web.
Because the app is sandboxed, all logos are stored in a folder in Library > Applikation Support.
My question is now, how I could distribute the already existing logos with an app bundle?
The best way would be, if the app launches the first time, the logo-folder inside Application Support gets created and all Logos are copied from the bundle inside the new folder.
Is this possible with an app bundle or do I have to create an installer?
Any help would be much appreciated.
Let's see if we can round out the comments you've received so far.
My question is now, how I could distribute the already existing logos with an app bundle?
Short answer: just include them in the bundle as resources. Many applications include images for use in their GUI the only difference you have is maybe its a "huge number".
Long answer:
Here is the outline one way to do it:
Create a Group in Xcode, say Logos, which is associated with a folder (in Xcode 9 New Group generates the folder, prior to that you can create the folder-less Group and then use the File Inspector to add one).
Add your logos to this group. Do not mark these images as part of your target (otherwise Xcode will copy and flatten your folder structure)
Add a Copy Files or Run Script Build Phase to copy the images to a subfolder of Resources, say Logos.
As the images are part of your app bundle you can access them directly from there using standard bundle and file routines. There is no need to copy them anywhere.
Finally you managed to cause some confusion with the statement:
Because the app is sandboxed, all logos are stored in a folder in Library > Applikation Support.
It is unclear which folder you mean here, there are three obvious candidates:
System: /Library/Application Support
User: ~/Library/Application Support
Sandboxed App: ~/Library/Containers/<bundle id>/Data/Library/Application Support
If you are using the APIs (URLsForDirectory:inDomains:, URLForDirectory:inDomain:appropriateForURL:create:error:, NSSearchPathForDirectoriesInDomains), request the user domain, and are in a sandboxed app then (3) is returned instead of (2) and your sandboxed app has access to it with asking permission from the user.
A subfolder of Application Support (whichever one you use but (3) is recommended), typically named according to the bundle ID of your app, is the place you should store logos your app downloads – there is no need to copy images you include in your app bundle into the same location.
HTH

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.

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

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.

MonoTouch - How to specify image path of UIImage.FromFile()

I have a path problem with UIImage.FromFile() method. My solution folder has 3 projects and the main UI project has an Images folder in it. I put all my project images in this folder and I have code like this:
UIImage myImg = UIImage.FromFile("Images/someImage.png");
I have already examined this and all these topics..
I set images property of build to "content" and etc..
Can you help me:
step by step adding an image to a specific project folder and use it dynamically
how to use NSBundle and why we have to use this?
Generally, if you have right clicked on the file, gone to it's properties and marked it as Content then the following will work:
UIImage myImg = UIImage.FromFile(#"Images/someImage.png");
The very first question you linked to has the solution - you need to use Unix style paths ("/"), not DOS/Windows paths ("\").
You should also carefully check the casing of your paths - the emulator is more forgiving of incorrect case than the actual device is.
Finally, look inside of your .app bundle to verify that the image files are really where you think they are, relative to the root of the bundle.

Resources