I have a private library which contains image assets for many of my apps. I include this library using CocoaPods in my app, using a local path and use_frameworks!.
I use the following code for opening an image from the bundle included in the library:
NSBundle *podBundle = [NSBundle bundleForClass:[self classForCoder]];
NSBundle *imagesBundle = [NSBundle bundleWithURL:[podBundle URLForResource:#"LibKwindoo" withExtension:#"bundle"]];
self.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"ImageName"] inBundle:imagesBundle compatibleWithTraitCollection:nil];
This worked fine until iOS 16, and works still fine under iOS 15 when I compile using iOS 16 SDK, but on iOS 16, the image gets just nil. The bundles seem to be correct. I also checked and the files are present in the compiled .car asset bundle which is included in the .app.
UPDATE: Even stranger: I experience this only when running the app from Xcode on the device or in the Simulator. When I run the same app independently on the device, it works!
What changed on iOS 16 which prevents me to load images from this asset bundle?
Related
I notice that when I use an asset catalog to specify my iOS app's icon, the resulting app has both an Assets.car file with the icons in it, as well as the individual icon files in the root bundle directory.
The app has iOS 9 as its deployment target.
I'm checking the resulting bundle by archiving the project and exporting it (via Xcode's Organizer window) as an Ad Hoc build with the App Thinning option set to iPhone 6s. This is on Xcode 9.3.1.
When I inspect the Assets.car file in the thinned app, I see that it only has the size 40, 58, 80, 114, and 120 icons (as well as a 200x178 image that the asset catalog viewer calls ZZZZPackedAsset-2.0 which contains 4 versions of the icon embedded in it which I've measured to be sizes: 42, 60, 82, and 116).
The icon files in the root bundle directory are the following:
AppIcon20x20#2x.png
AppIcon20x20#2x~ipad.png
AppIcon20x20#3x.png
AppIcon20x20~ipad.png
AppIcon29x29.png
AppIcon29x29#2x.png
AppIcon29x29#2x~ipad.png
AppIcon29x29#3x.png
AppIcon29x29~ipad.png
AppIcon40x40#2x.png
AppIcon40x40#2x~ipad.png
AppIcon40x40#3x.png
AppIcon40x40~ipad.png
AppIcon50x50#2x~ipad.png
AppIcon50x50~ipad.png
AppIcon57x57.png
AppIcon57x57#2x.png
AppIcon60x60#2x.png
AppIcon60x60#3x.png
AppIcon72x72#2x~ipad.png
AppIcon72x72~ipad.png
AppIcon76x76#2x~ipad.png
AppIcon76x76~ipad.png
AppIcon83.5x83.5#2x~ipad.png
So I have two questions:
Why are icon assets duplicated as external AppIcon*.png files and internal Assets.car assets?
Why do the individual AppIcon*.png include all of the icons and not just the ones need?
I was under the impression that iOS 9+ can use the asset catalog for its icon assets. Is this just a discrepancy in the bundle that Xcode produces versus what will happen on the app store? Or is it an incorrect assumption that I'm making about how the app thinning app export option works?
With regard to the app icons, the asset catalog is a human labor-saving device, not a space-saving device.
Historically, there were not always asset catalogs; instead, the iOS system on the device expects to find the app icons at the top level of the app bundle, with highly specific names derived from a name specified in the Info.plist.
You could configure that yourself, and that's what we used to have to do.
But to save you the trouble of worrying about that, you are offered the option to put the app icons in the asset catalog instead — and then the app-building process does for you what you would previously have done yourself, writing the icons out to the top level of the app bundle and modifying the Info.plist to point to them.
I need to access a file from my main app in my share extension is that possible? The file is the "bundle" for distribution for a react native iOS app, something like
jsCodeLocation = [[NSBundle mainBundle] URLForResource:#"main" withExtension:#"jsbundle" subdirectory:#"../myMainProject"];
If I copy and paste the main.jsbundle file on my share extension it works fine.
Or should I place this main.jsbundle in an app group so both app and extension can use it?
An app and its extensions can only share data over a common app group folder, and both must be added explicitly in Xcode to that group.
If your JavaScript bundle is static and is delivered with your app, you max place it as a resource into a shared framework, and add this framework to both app and extension. So you can access this bundle by
jsCodeLocation = [[NSBundle bundleWithIdentifier: <framework identifier>] URLForResource:#"main" withExtension:#"jsbundle"];
Note: You shouldn't access the contents of the parent folder of a bundle folder.
Here is the problem:
I am trying to check the contents of my app's bundle. So by writing a couple of lines of code like:
NSBundle *myBundle = [NSBundle mainBundle];
NSLog(#"%#",myBundle);
I got the path that I need to locate my app's bundle. However, when I deleted the bundle, I was expecting my app to give an error saying that bundle doesn't exist. Instead, it showed that same path again. Hy doesn't it have any impact on the program. How does it work under the hoods? I am new to iOS, so any help will be appreciated.
Thanks in advance!!!
This question already has answers here:
How to reduce the size of my iPhone application?
(7 answers)
Closed 4 years ago.
Following this how to reduce the size of app
My ipa size is 19 MB . Renamed the file with a .zip extension and double click on it. Found the app in the Payload folder and right mouse click on it and choose show package contents. Found exec to be 25MB and some images of large size.How can I reduce the size of exec? because I want to reduce the size of app in store
Any ideas / suggestions would be highly helpful
You can load high-res images from internet
Optimize splash screen images, remove alpha, make 8bit color
Use pseudo-AJPEG image.png + image_mask.jpg
#define maskedCacheStorePath [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"maskedImageCache"]
+ (UIImage *)maskedImageNamed:(NSString *)imageName useCache:(Boolean)useCache {
NSString *imageCacheStoreFile = nil;
if (useCache) {
if (![[NSFileManager defaultManager] fileExistsAtPath:maskedCacheStorePath])
[[NSFileManager defaultManager] createDirectoryAtPath:maskedCacheStorePath withIntermediateDirectories:YES attributes:nil error:nil];
imageCacheStoreFile = [maskedCacheStorePath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", imageName]];
if ([[NSFileManager defaultManager] fileExistsAtPath:imageCacheStoreFile])
return [UIImage imageWithContentsOfFile:imageCacheStoreFile];
}
UIImage *image = [UIImage imageNamed:[imageName stringByAppendingPathExtension:#"jpg"]];
UIImage *mask = [UIImage imageNamed:[[imageName stringByAppendingString:#"_mask"] stringByAppendingPathExtension:#"png"]];
CGImageRef ref = CGImageCreateWithMask(image.CGImage, mask.CGImage);
UIImage *result = [UIImage imageWithCGImage:ref scale:image.scale orientation:image.imageOrientation];
CGImageRelease(ref);
if (useCache && result)
[UIImagePNGRepresentation(result) writeToFile:imageCacheStoreFile atomically:YES];
return result;
}
also look through this question answers
look at this technical Q&A on Apple Developer site.
It should contain all tips for reduce your ipa size ;)
Below is an excerpt from that document that may get you started:
Measure Your App Before trying any optimizations, you should measure.
Some of the techniques in this document are tradeoffs with downsides
that must be considered. You must measure their impact to be sure
you're making the right tradeoff. Without measuring, you can't know
what kind of change you're making.
The app distribution process produces a number of different artifacts,
each with its own purpose and size. It's important to understand what
each artifact represents and which artifacts to use when measuring
your app's size.
An app bundle is the .app bundle containing all of the binaries in your app, plus all of your app's resources, such as images. This
bundle contains everything needed for your app to run on every
supported device. For the purposes of this document, an app bundle
only refers to the .app produced by archiving your app.
An App Store submission .ipa is created from an Xcode archive when uploading to the App Store or by exporting the archive for iOS
App Store Deployment. This .ipa is a compressed directory
containing the app bundle and additional resources needed for App
Store services, such as .dSYM files for crash reporting and asset
packs for On Demand Resources.
A universal .ipa is a compressed app bundle that contains all of the resources to run the app on any device. Bitcode has been
recompiled, and additional resources needed by the App Store, such as
.dSYM files and On Demand Resources, are removed. For App Store apps,
this .ipa is downloaded to devices running iOS 8 or earlier.
A thinned .ipa is a compressed app bundle that contains only the resources needed to run the app on a specific device. Bitcode has
been recompiled, and additional resources needed by the App Store,
such as .dSYM files and On Demand Resources, are removed. For App
Store apps, this .ipa is downloaded to devices running iOS 9 or
later.
A universal app bundle is the decompressed universal .ipa. The installation process decompresses the universal .ipa and installs the
universal app bundle.
A thinned app bundle is the decompressed thinned .ipa. The installation process decompresses the thinned .ipa and installs the
thinned app bundle.
This is similar to this question: iOS Objective-C Image file name/path different behavior betwewen simulator and device
I have the following path in Xcode, where Landscape is a Folder, not a Group:
Resources/Landscape/clouds_high.png
Both these load the image in the Simulator:
// Version A. Should only work for Groups, where image is in root
[CCSprite spriteWithFile:#"clouds_high.png"];
// Version B. Should work for my case (with a Landscape Folder)
[CCSprite spriteWithFile:#"Landscape/clouds_high.png"];
However, as expected, only the second works on the iOS device. I'm aware of differences in case causing things like this, but why does the first version with an invalid path still work in the Simulator?
For the record, if I make a duplicate of clouds_high.png just in the Resources directory, then the Simulator picks this version over the original in Landscape for Version A. Using Version B causes the simulator to choose the one in Landscape as expected. But as I mentioned before, the iOS device only works with the path specified relative to Resources. Why is this?
Try using this to get your paths. It will never fail, neither in the simulator nor on the device unless the file name you provide is invalid.
[[NSBundle mainBundle] pathForResource:#"clouds_high" ofType:#"png"];
For your case:
[CCSprite spriteWithFile:[[NSBundle mainBundle] pathForResource:#"clouds_high" ofType:#"png"]];