iOS如何在SDK中使用資原始檔(xib,image,localizable string...)
需求:在SDK中使用資原始檔,例如xib, image, 字串國際化等等.
閱讀前提:
- 瞭解如何建立SDK
- 瞭解如何在一個專案中匯入並使用SDK
GitHub地址(附程式碼) : 如何在SDK中使用資原始檔
簡書地址 : 如何在SDK中使用資原始檔
部落格地址 : 如何在SDK中使用資原始檔
掘金地址 : 如何在SDK中使用資原始檔
原理
SDK中使用xib,圖片或者其他資原始檔時不同於直接在一個專案中使用的方法,因為我們必須明確一點,SDK中只有.h,.m,.mm,.swift等檔案可以直接匯入使用,像圖片,xib檔案,做國際化的.string檔案等資原始檔無法直接通過載入Framework的路徑找到,我們必須要在專案Build Phases的Copy Bundle Resources新增我們需要使用的資原始檔(nib, image, .string...),因此,我們最好在SDK中新建一個Bundle檔案存放所有的資原始檔,然後在主工程中Copy Bundle Resources新增該bundle檔案即可載入所有SDK中的資原始檔.
建立Bundle
為了統一存放SDK中所有資原始檔
注意:我們需要在每次編譯完成後手動或寫指令碼自動將資原始檔拷貝到Bundle中以至於才能在主工程中生效。
此後我們在SDK專案所用到的所有資原始檔都應該放到Bundle之中。
情景分類
一.使用Xib檔案
1. Build SDK工程
如果專案中包含xib檔案,則專案每次編譯後會在Framework中將自動生成nib檔案,如下圖所示
2.將新編譯好的Framework放入工程中
- 首先拷貝編譯好的framework到我們工程目錄中(即工程中進入Framework,不會自行百度)
- 使用Nib檔案分為兩種方式
- 直接將Nib檔案匯入主專案資原始檔中
- (推薦)將Framework中編譯好的Nib檔案放入Bundle中,再將Bundle匯入專案的資原始檔中,好處是可以統一管理一個Framework中所有的資原始檔
如果只使用nib則如下圖,否則可按相同方式將bundle匯入專案
3. 使用SDK中的xib檔案
- 直接使用framework中的nib檔案
NSString *path = [[NSBundle mainBundle] pathForResource:@"XDXTestFramework" ofType:@"framework"];
TestJumpVC *vc = [[TestJumpVC alloc] initWithNibName:@"TestJumpVC" bundle:[NSBundle bundleWithPath:path]];
[self presentViewController:vc animated:YES completion:nil];
複製程式碼
- (推薦)使用framework中bundle中的nib檔案。
因為我們在第二步中已經將bundle放入專案的copy bundle resources中,所以下面程式碼中使用
[NSBundle mainBundle]
NSString *path = [[NSBundle mainBundle] pathForResource:@"XDXAllResources" ofType:@"bundle"];
TestJumpVC *vc = [[TestJumpVC alloc] initWithNibName:@"TestJumpVC" bundle:[NSBundle bundleWithPath:[path stringByAppendingString:@"/xibs"]]];
[self presentViewController:vc animated:YES completion:nil];
複製程式碼
如果未進行第2步中將nib檔案匯入專案則程式會crash,並提示“Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </var/containers/Bundle/Application/D46C1A83-E6F4-4DB2-8F02-EC0ED05C6C99/XDXSDKResourceFileDemo.app> (loaded)' with name 'TestJumpVC''”
二.使用圖片
1. 將圖片拷貝到Framework中建立好的bundle中
2. 使用圖片,載入bundle中圖片的路徑(Note:必須與真實路徑相同,可參考Demo)
// Test image
NSString *path = [[[NSBundle mainBundle] pathForResource:@"XDXAllResources" ofType:@"bundle"] stringByAppendingString:@"/images/1.png"];
self.testImage.image = [UIImage imageWithContentsOfFile:path];
複製程式碼
三.使用國際化語言適配(中英文適配)
1.建立.string型別檔案以支援中英文
2. 設定strings檔案的Localize使其支援多種語言
3. 設定專案支援多種語音
4. 在多語言檔案中新增對應的字元
5. 建立NSBundle分類提供類方法以支援在SDK中使用多語言
原理同上,即在budle中找到對應的中英文sting檔案,然後利用- (NSString *)localizedStringForKey:(NSString *)key value:(nullable NSString *)value table:(nullable NSString *)tableName NS_FORMAT_ARGUMENT(1);
方法來檢索bundle中對應語言的字串。
程式碼中涉及APP手動選擇中英文模式,而我們這裡主要實現根據系統當前設定的語言環境,所以忽略人為設定語言的情況
// Note : Be consistent with you create bundle‘s name.
#define XDXRouterResBundle @"XDXAllResources"
@implementation NSBundle (XDXLocalizable)
+ (instancetype)XDX_localizableBundleWithBundleName:(NSString *)bundleName {
static NSBundle *localizableBundle = nil;
if (localizableBundle == nil) {
if (!bundleName) {
bundleName = XDXRouterResBundle;
}
NSString *bundleType = nil;
if (bundleName && ![bundleName hasSuffix:@"bundle"]) {
bundleType = @"bundle";
}
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:bundleName ofType:bundleType];
localizableBundle = [NSBundle bundleWithPath:bundlePath];
}
return localizableBundle;
}
+ (NSString *)XDX_localizedStringForKey:(NSString *)key {
return [self XDX_localizedStringForKey:key value:nil];
}
+ (NSString *)XDX_localizedStringForKey:(NSString *)key value:(NSString *)value{
NSBundle *bundle = nil;
//NSString *language = [self getLanguageFromSystem];
//NSString *language = [self getLanguageFromPlist];
NSString * language = [self getLanguageFromDevelopersSetup];
if (!language) {
language = [self getLanguageFromSystem];
NSLog(@"Current language is %@",language);
}
//從FrameworkTestBundle.bundle中查詢資源
NSString *bundlePath = [[NSBundle XDX_localizableBundleWithBundleName:nil] pathForResource:language ofType:@"lproj"];
bundle = [NSBundle bundleWithPath:bundlePath];
value = [bundle localizedStringForKey:key value:value table:nil];
return [[NSBundle mainBundle] localizedStringForKey:key value:value table:nil];
}
//這個設定語言是通過讀取當前系統使用語言
+ (NSString *)getLanguageFromSystem{
NSString *language = [NSLocale preferredLanguages].firstObject;
if ([language hasPrefix:@"en"]) {
language = @"en";
} else if ([language hasPrefix:@"zh"]) {
if ([language rangeOfString:@"Hans"].location != NSNotFound) {
language = @"zh-Hans"; // 簡體中文
} else {
language = @"zh-Hant"; // 繁體中文
}
} else {
language = @"en";
}
return language;
}
//這個是設定語言通過Plist檔案來讀取
+ (NSString *)getLanguageFromPlist{
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"SDKInternationalizationDemoPlist.plist" ofType:nil];
if (!bundlePath) {
return nil;
}
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:bundlePath];
if (dict) {
NSInteger languageNum = [[dict valueForKey:@"language"] integerValue];
switch (languageNum) {
case 1:
return @"en"; //語言為英語:en
break;
case 2:
return @"zh-Hans";//語言為簡中:zh-Hans
break;
case 3:
return @"zh-Hant";//語言為繁中:zh-Hanz
break;
default:
return @"en";
break;
}
}
return @"en";
}
//這個是設定語言通過開發者手動呼叫,從NSUserDefaults裡面去讀kDSADLanguageStyle這個欄位是哪一種語言
+ (NSString *)getLanguageFromDevelopersSetup{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSInteger languageStyle = [[userDefaults valueForKey:@"TODO"] integerValue];
if (!languageStyle) {
return nil;
}
switch (languageStyle) {
case 1:
return @"en";
break;
case 2:
return @"zh-Hans";
break;
case 3:
return @"zh-Hant";
break;
default:
return @"en";
break;
}
}
@end
複製程式碼
6.在程式碼中使用多語言字串
self.testLabel.text = [NSBundle XDX_localizedStringForKey:@"Test"];
複製程式碼
附:在Framework每次編譯後新增指令碼來拷貝資原始檔到Bundle中
原因
每當資原始檔有所改動,例如圖片的增加減少,strings檔案中新增新欄位等等,我們都需要手動將新的檔案放入Bundle對應的資料夾下,如果我們想利用指令碼自動放所有資原始檔,可利用Xcode特性。
操作
-
首先,在專案中新建一個指令碼
-
其次,在指令碼中將我們專案的所有資原始檔拷貝到bundle中對應的目錄下(注意:檔案路徑必須正確,如遇到Framework中的nib檔案,專案的位置在個人電腦中是不用的,需要查詢並修改)
-
最後,我們在Build完專案後,所有資原始檔會更新到最新