Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing bundled assets between app and extension

Tags:

My Photo Sharing extension plans to use the same design assets (for navigation and for adding 'stamps / stickers' to the photo).

As explained in App Sandbox Design Guide, groups of sandboxed apps that need to share files and other information can request a container directory as part of their entitlements. These directories are stored in ~/Library/Group Containers/. https://developer.apple.com/documentation/foundation/nsfilemanager/1412643-containerurlforsecurityapplicati

Currently the assets are bundled in or downloaded and added to the Documents folder. If I want to use the assets in the Photo Sharing extension, would it make sense to put everything in the ~/Library/Group Containers/ and both the container app and the extension get the assets from there?

like image 487
daihovey Avatar asked Aug 06 '14 00:08

daihovey


People also ask

What is an iOS app bundle?

App bundles make it easy for customers to buy up to 10 of your apps or games in a single purchase. You can create app bundles for paid apps or free apps that offer an auto-renewable subscription to access all apps in the bundle. Learn how to set up app bundles and effectively market them on your product page.

What is Share extension in iOS?

Share Extension is an easy way that Apple provides to share contents (images, audio, files, etc.) from one app to another, even made by different developers.

What is the use of bundle in Swift?

The bundle object provides a single interface for locating items, taking into account the bundle structure, user preferences, available localizations, and other relevant factors. Any executable can use a bundle object to locate resources, either inside an app's bundle or in a known bundle located elsewhere.

How do I add an extension to an app in Xcode?

In Xcode, click File > New > Target… then choose the extension you want and click next. You'll want to make sure all the team/organization information is correct and use a similar bundle id to your main app. For example, if your main app's bundle id is com.


2 Answers

Regarding sharing data:

If you want to share files between your iOS8 extension and your Containing app, you want to write files to a shared container or use the shared user defaults.

From Apple's iOS8 current documentation:

By default, your containing app and its extensions have no direct access to each other’s containers

You want to create an App Group, and add your containing app and its extensions to this group. This is pretty simple using Xcode 6, here's how to do it in xcode:

how to create an app group using xcode 6

In the app group name, input a constant like:

group.com.bundle.app.soething 

This creates a shared container for your containing app and extension, which allows:

  • Share NSUserDefaults:

    [[NSUserDefaults alloc] initWithSuiteName:@"group.com.bundle.app.soething"]; 
  • Share a directory on the filesystem:

    NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.bundle.app.soething"]; 

EDIT This will print out all the path combinations we have:

// App group's path  NSURL  *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.test.app"];  NSLog(@"App group: %@", containerURL.path);    // Bundle path  NSLog (@"Bundle: %@", [[NSBundle mainBundle] bundlePath]);    // Good old Documents path  NSArray *Paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);  NSString *path = [Paths objectAtIndex:0];  NSLog(@"Documents: %@ ", path); 

EDIT - and for Swift:

  • Share NSUserDefaults:

    var sharedDefaults = NSUserDefaults(suiteName: "group.com.bundle.app.soething") 
  • Share a directory on the filesystem:

    var containerURL = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier("group.com.bundle.app.soething")! 

I hope this helps you :)

Resources: Apple's iOS8.0 Extensions Development Guide - https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW1

Apple's iOS8.0 NSFileManager Class Reference - https://developer.apple.com/documentation/foundation/nsfilemanager/1412643-containerurlforsecurityapplicati

like image 155
nurnachman Avatar answered Sep 30 '22 23:09

nurnachman


I need to share bundled resources between the app and extension. At first, I was thinking I could copy them into the shared group area on first launch, but what if the user calls up the extension and never launches the app?

As mxcl notes, you can include the assets in both targets but that will expand the size of your final submitted binary.

I've confirmed putting assets in a framework works in Xcode 6.1 (it may have worked before, but I'm just trying it now):

You can have standalone images in your framework or an asset catalog. Both will work.

In the framework, just set up a class with accessor methods that return UIImage objects. Something like this (Objective-C):

@implementation AssetService + (UIImage *)frameworkImageNamed:(NSString *)name {   return [UIImage imageNamed:name           inBundle:[NSBundle bundleForClass:[self class]]           compatibleWithTraitCollection:nil]; } @end 

Or in Swift:

public class AssetService {   public init() {   }    // class method version   public class func frameworkImageNamed(name: String) -> UIImage? {     return UIImage(named: name,                    inBundle: NSBundle(forClass: AssetService.self),                    compatibleWithTraitCollection: nil)!   } } 

Note that since the above code is inside the framework but will run in "app space" you need to specify the bundle.

Then, your app or extension can just link in the framework, and call [AssetService frameworkImageNamed:@"myimage"] or AssetService.frameworkImageNamed("myimage").

Caveat: despite returning an optional UIImage? the code gets very angry if it can't find the image named and will crash. But if it's your own framework, you should know what's in there and catch this kind of bug.

like image 27
gregheo Avatar answered Sep 30 '22 22:09

gregheo