步骤如下:
首先在App Store中下载 Apple Configurator 2 这个软件
-
数据线连上手机,登录账户(APPLE ID),正常连上手机之后是这样的
-
选中手机,点击添加->应用
-
在应用列表中选中想获取资源的应用,选中后点击添加
-
然后应用会显示在添加中,等待
-
下载完毕后可能出现冲突,不用管,直接打开一个finder,快捷键shift+command+G,进入
'~/Library/Group Containers/K36BKF7T3D.group.com.apple.configurator/Library/Caches/Assets/TemporaryItems/MobileApps/',
就可以找到需要的资源的.ipa文件,⚠️注意:要拷贝出去,过一会可能会消失哦
-
将.ipa改成.zip解压,解压后的层次结构如下,可以看到.app文件。直接删除.app后缀,会变成一个资源文件夹。
.app文件中包含Assets资源、可执行文件、Framework、bundle、其他(数据库、应用启动图、应用图标、国际化资源、nib、sb、plist、json、字体...)
- 下载cartool
-
编辑scheme
-
设置资源路径和解压路径
- 设置好运行,不报错的话,图片资源都能正常在解压路径
- 如果报错。替换cartoon -> main.m 文件
//
// main.m
// cartool
//
// Created by Steven Troughton-Smith on 14/07/2013.
// Copyright (c) 2013 High Caffeine Content. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef enum _kCoreThemeIdiom {
kCoreThemeIdiomUniversal,
kCoreThemeIdiomPhone,
kCoreThemeIdiomPad,
kCoreThemeIdiomTV,
kCoreThemeIdiomCar,
kCoreThemeIdiomWatch,
kCoreThemeIdiomMarketing
} kCoreThemeIdiom;
typedef NS_ENUM(NSInteger, UIUserInterfaceSizeClass) {
UIUserInterfaceSizeClassUnspecified = 0,
UIUserInterfaceSizeClassCompact = 1,
UIUserInterfaceSizeClassRegular = 2,
};
@interface CUICommonAssetStorage : NSObject
-(NSArray *)allAssetKeys;
-(NSArray *)allRenditionNames;
-(id)initWithPath:(NSString *)p;
-(NSString *)versionString;
@end
@interface CUINamedImage : NSObject
@property(readonly) CGSize size;
@property(readonly) CGFloat scale;
@property(readonly) kCoreThemeIdiom idiom;
@property(readonly) UIUserInterfaceSizeClass sizeClassHorizontal;
@property(readonly) UIUserInterfaceSizeClass sizeClassVertical;
-(CGImageRef)image;
@end
@interface CUIRenditionKey : NSObject
@end
@interface CUIThemeFacet : NSObject
+(CUIThemeFacet *)themeWithContentsOfURL:(NSURL *)u error:(NSError **)e;
@end
@interface CUICatalog : NSObject
@property(readonly) bool isVectorBased;
-(id)initWithURL:(NSURL *)URL error:(NSError **)error;
-(id)initWithName:(NSString *)n fromBundle:(NSBundle *)b;
-(id)allKeys;
-(id)allImageNames;
-(CUINamedImage *)imageWithName:(NSString *)n scaleFactor:(CGFloat)s;
-(CUINamedImage *)imageWithName:(NSString *)n scaleFactor:(CGFloat)s deviceIdiom:(int)idiom;
-(NSArray *)imagesWithName:(NSString *)n;
@end
void CGImageWriteToFile(CGImageRef image, NSString *path)
{
CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:path];
CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypePNG, 1, NULL);
CGImageDestinationAddImage(destination, image, nil);
if (!CGImageDestinationFinalize(destination)) {
NSLog(@"Failed to write image to %@", path);
}
CFRelease(destination);
}
NSString *idiomSuffixForCoreThemeIdiom(kCoreThemeIdiom idiom)
{
switch (idiom) {
case kCoreThemeIdiomUniversal:
return @"";
break;
case kCoreThemeIdiomPhone:
return @"~iphone";
break;
case kCoreThemeIdiomPad:
return @"~ipad";
break;
case kCoreThemeIdiomTV:
return @"~tv";
break;
case kCoreThemeIdiomCar:
return @"~carplay";
break;
case kCoreThemeIdiomWatch:
return @"~watch";
break;
case kCoreThemeIdiomMarketing:
return @"~marketing";
break;
default:
break;
}
return @"";
}
NSString *sizeClassSuffixForSizeClass(UIUserInterfaceSizeClass sizeClass)
{
switch (sizeClass)
{
case UIUserInterfaceSizeClassCompact:
return @"C";
break;
case UIUserInterfaceSizeClassRegular:
return @"R";
break;
default:
return @"A";
}
}
NSMutableArray *getImagesArray(CUICatalog *catalog, NSString *key)
{
NSMutableArray *images = [[NSMutableArray alloc] initWithCapacity:5];
for (NSNumber *scaleFactor in @[@1, @2, @3])
{
CUINamedImage *image = [catalog imageWithName:key scaleFactor:scaleFactor.doubleValue];
if (image && image.scale == scaleFactor.floatValue) [images addObject:image];
}
return images;
}
void exportCarFileAtPath(NSString * carPath, NSString *outputDirectoryPath)
{
NSError *error = nil;
outputDirectoryPath = [outputDirectoryPath stringByExpandingTildeInPath];
// CUIThemeFacet *facet = [CUIThemeFacet themeWithContentsOfURL:[NSURL fileURLWithPath:carPath] error:&error];
//
// CUICatalog *catalog = [[CUICatalog alloc] init];
//
// /* Override CUICatalog to point to a file rather than a bundle */
// [catalog setValue:facet forKey:@"_storageRef"];
/* CUICommonAssetStorage won't link */
CUICatalog *catalog = nil;
if ([CUICatalog instancesRespondToSelector:@selector(initWithURL:error:)]) {
/* If CUICatalog has the URL API (Mojave), use it. */
catalog = [[CUICatalog alloc] initWithURL:[NSURL fileURLWithPath:carPath] error:&error];
} else {
CUIThemeFacet *facet = [CUIThemeFacet themeWithContentsOfURL:[NSURL fileURLWithPath:carPath] error:&error];
catalog = [[CUICatalog alloc] init];
/* Override CUICatalog to point to a file rather than a bundle */
[catalog setValue:facet forKey:@"_storageRef"];
}
NSCAssert(!error, @"Error attempting to open asset catalog (%@): %@", carPath, error);
CUICommonAssetStorage *storage = [[NSClassFromString(@"CUICommonAssetStorage") alloc] initWithPath:carPath];
for (NSString *key in [storage allRenditionNames])
{
printf("%s\n", [key UTF8String]);
NSArray* pathComponents = [key pathComponents];
if (pathComponents.count > 1)
{
// Create subdirectories for namespaced assets (those with names like "some/namespace/image-name")
NSArray* subdirectoryComponents = [pathComponents subarrayWithRange:NSMakeRange(0, pathComponents.count - 1)];
NSString* subdirectoryPath = [outputDirectoryPath copy];
for (NSString* pathComponent in subdirectoryComponents)
{
subdirectoryPath = [subdirectoryPath stringByAppendingPathComponent:pathComponent];
}
[[NSFileManager defaultManager] createDirectoryAtPath:subdirectoryPath
withIntermediateDirectories:YES
attributes:nil
error:&error];
}
NSMutableArray *images = getImagesArray(catalog, key);
for( CUINamedImage *image in images )
{
if( CGSizeEqualToSize(image.size, CGSizeZero) )
printf("\tnil image?\n");
else
{
CGImageRef cgImage = [image image];
NSString *idiomSuffix = idiomSuffixForCoreThemeIdiom(image.idiom);
NSString *sizeClassSuffix = @"";
if (image.sizeClassHorizontal || image.sizeClassVertical)
{
sizeClassSuffix = [NSString stringWithFormat:@"-%@x%@", sizeClassSuffixForSizeClass(image.sizeClassHorizontal), sizeClassSuffixForSizeClass(image.sizeClassVertical)];
}
NSString *scale = image.scale > 1.0 ? [NSString stringWithFormat:@"@%dx", (int)floor(image.scale)] : @"";
NSString *name = [NSString stringWithFormat:@"%@%@%@%@.png", key, idiomSuffix, sizeClassSuffix, scale];
printf("\t%s\n", [name UTF8String]);
if( outputDirectoryPath )
CGImageWriteToFile(cgImage, [outputDirectoryPath stringByAppendingPathComponent:name]);
}
}
}
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
if (argc < 2)
{
printf("Usage: cartool <path to Assets.car> [outputDirectory]\n");
return -1;
}
exportCarFileAtPath([NSString stringWithUTF8String:argv[1]], argc > 2 ? [NSString stringWithUTF8String:argv[2]] : nil);
}
return 0;
}