App Settings.Bundle
寫在前邊
Settings.Bundle 是App的配置項(xiàng), 用戶和測(cè)試可以在外圍對(duì)于App的部分信息進(jìn)行修改, 是的App的運(yùn)行環(huán)境變的可配置, 對(duì)于測(cè)試尤其使用.
我們也可以結(jié)合Build Configuration針對(duì)不同的編譯環(huán)境進(jìn)行個(gè)性化設(shè)置, 當(dāng)然, 包括移除Setting(有時(shí)候Production版本是不需要Setting的)
本文分為三個(gè)部分:
- Setting 用法: 詳細(xì)的數(shù)據(jù)結(jié)構(gòu)
- 應(yīng)用場(chǎng)景: 使用注意事項(xiàng)
- 動(dòng)態(tài)配置: 動(dòng)態(tài)添加Setting
Setting 用法
Settings.Bundle支持六種配置項(xiàng)分別是:
- TextField
- MultiValue
- Title
- Group
- Slider
- ToggleSwitch
TextField
數(shù)據(jù)結(jié)構(gòu):
字段:
- Type 類型,默認(rèn)是 Text Field
- Title 顯示的Title
- Identifier 標(biāo)識(shí)符强衡,用來獲取配置項(xiàng)的配置內(nèi)容
- Default Value 默認(rèn)值
- Autocorrection Style 自動(dòng)糾錯(cuò)(我很討厭這個(gè)功能)
- Autocapitalization Style 大小寫類型(字符 句子 全部)
效果:
MultiValue
數(shù)據(jù)結(jié)構(gòu):
字段:
- Type 類型患蹂,默認(rèn)是 Multi Value
- Title 顯示的Title
- Identifier 標(biāo)識(shí)符喊括,用來獲取配置項(xiàng)的配置內(nèi)容
- Default Value 默認(rèn)值
- Values 可供選擇的值數(shù)組
- Titles 與選擇值對(duì)應(yīng)的顯示文本
效果:
Title
數(shù)據(jù)結(jié)構(gòu)1:
- Type 類型鸵膏,默認(rèn)是Title
- Title 顯示的Title
- Identifier 標(biāo)識(shí)符,用來獲取配置項(xiàng)的配置內(nèi)容
- Default Value 默認(rèn)值
效果:
數(shù)據(jù)結(jié)構(gòu)2:
- Values 可供選擇的值數(shù)組
- Titles 與選擇值對(duì)應(yīng)的顯示文本
相對(duì)于結(jié)構(gòu)1, 多出了Values和Titles兩個(gè)字段, 此時(shí)要注意的是, Default Value只能取自于Values中的某一個(gè)元素, 否則顯示為空
效果圖:
Group
Group可以認(rèn)為是一個(gè)用在做分組的文字, 就像Grouped TableView的效果
數(shù)據(jù)結(jié)構(gòu):
- Type 類型木柬,默認(rèn)是Group
- Title 顯示的Title
效果:
ToggleSwitch
選擇開關(guān)
數(shù)據(jù)結(jié)構(gòu):
- Type 類型间学,默認(rèn)是 Toggle Switch
- Title 顯示的Title
- Identifier 標(biāo)識(shí)符,用來獲取配置項(xiàng)的配置內(nèi)容
- Default Value 默認(rèn)值
- Value for OFF 關(guān)閉時(shí)對(duì)應(yīng)的值(貌似沒用)
- Value for ON 打開時(shí)對(duì)應(yīng)的值(貌似沒用)
效果圖:
Slider
數(shù)據(jù)結(jié)構(gòu):
- Type 類型嘹屯,默認(rèn)是 Slider
- Title 顯示的Title
- Identifier 標(biāo)識(shí)符攻询,用來獲取配置項(xiàng)的配置內(nèi)容
- Default Value 默認(rèn)值
- Minimum Value:最小值
- Maximun Value:最大值
- Min Value Image Filename:最小值端圖片
- Max Value Image Filename:最大值端圖片
注意:
Image Filename 不能放在主文件夾中,而是需要放在Settings捆綁包中州弟,才能夠通過 Min/Max Value Image Filename 設(shè)置使用, 如:
效果圖:
關(guān)于字段的官方說明:
[圖片上傳失敗...(image-ff291b-1534505621730)]
應(yīng)用場(chǎng)景
添加Settings.Bundle的最終目的還是和app進(jìn)行交互(廢話),Settings中的任何選型都可以用代碼獲得
it is important to understand that until the user actually changes the value of
the setting nothing is actually set. If you check for the setting in your
application it will actually return nil unless you set a default value.
需要注意的是, 在用戶實(shí)際修改了setting里的數(shù)據(jù)之前 , 這時(shí)配置數(shù)據(jù)并沒有真正的寫入到app的NSUserDefaults
中, 此時(shí)用NSUserDefaults
獲取的值都是空的. 比如,直接調(diào)用以下代碼:
- (void)testSetting {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *text = [defaults valueForKey:@"selecter"];
if (text) {
NSLog(text);
} else {
NSLog(@"nothing");
}
}
結(jié)果將是:
2018-08-17 18:01:27.920247+0800 AppSetting[8672:394359] nothing
也就是說此時(shí)的setting并未生效, 但是如果用戶在setting中修改過selecter
(setting中的選項(xiàng)
)一個(gè)值, 獲得的數(shù)據(jù)將不為空:
2018-08-17 18:08:22.177436+0800 AppSetting[8795:404984] 1
對(duì)此, 我們的處理方案是, 在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法中調(diào)用以下函數(shù), 將所有的setting數(shù)據(jù)注冊(cè)到app中:
- (void)registerDefaultsFromSettingsBundle
{
NSString *settingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
if(!settingsBundle) {
NSLog(@"Could not find Settings.bundle");
return;
}
NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[settingsBundle stringByAppendingPathComponent:@"Root.plist"]];
NSArray *preferences = [settings objectForKey:@"PreferenceSpecifiers"];
NSMutableDictionary *defaultsToRegister = [[NSMutableDictionary alloc] initWithCapacity:[preferences count]];
for(NSDictionary *prefSpecification in preferences) {
NSString *key = [prefSpecification objectForKey:@"Key"];
if(key) {
[defaultsToRegister setObject:[prefSpecification objectForKey:@"DefaultValue"] forKey:key];
}
}
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsToRegister];
}
動(dòng)態(tài)配置
一般情況下, 我的環(huán)境配置(Build Configuration)至少分四種:
- Dev 開發(fā)
- Release 測(cè)試
- Staging 預(yù)發(fā)布
- Production 生產(chǎn)
然后分別給予不同的宏定義, 以保證我們切換編譯環(huán)境時(shí), 做到代碼零修改, Build Configuration配置
1. 創(chuàng)建工程 DynamicSetting
2. 創(chuàng)建相關(guān)目錄
在工程目錄下創(chuàng)建文件夾Setting
以及子文件夾Release
和Staging
(一般生產(chǎn)環(huán)境不需要setting, 當(dāng)然這要依據(jù)具體的業(yè)務(wù)需求), 并添加到工程中(不添加到工程也行, 此處只是為了方便修改)
3. 創(chuàng)建配置
點(diǎn)擊工程文件, 選中info
, 在Configurations
下點(diǎn)擊+
, 復(fù)制一個(gè)Configuration
(我一般復(fù)制Release
, 這樣發(fā)出去的ipa都去掉日志等不必要的操作 具體依據(jù)業(yè)務(wù)需求修改)
4. 添加Setting.bundle
新建Setting.Bundle, 但不要添加到當(dāng)前Target
中, 并分別保存到Release
和Staging
文件夾下:
不要添加到當(dāng)前Target
中
不要添加到當(dāng)前Target
中
不要添加到當(dāng)前Target
中
創(chuàng)建完成后的工程, 是這個(gè)樣子的:
運(yùn)行XCode, 我們?cè)谀M器中的Setting
中找不到對(duì)應(yīng)的DynamicSetting
(廢話, 都沒添加到Target
, 能顯示才怪!!!)
5. 添加拷貝腳本
不添加到Target
的原因就是 , 我們要用腳本吧Setting.Bundle
拷貝到ipa中.
選中"Target", 切換到Build Phases
, 點(diǎn)擊+
, 選中New Run Script Phase
,
添加腳本:
if [ ${CONFIGURATION} = "Debug" ]; then
cp -r ${PROJECT_DIR}/${PROJECT_NAME}/Setting/Release/Settings.bundle ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
fi
if [ ${CONFIGURATION} = "Release" ]; then
cp -r ${PROJECT_DIR}/${PROJECT_NAME}/Setting/Release/Settings.bundle ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
fi
if [ ${CONFIGURATION} = "Staging" ]; then
cp -r ${PROJECT_DIR}/${PROJECT_NAME}/Setting/Staging/Settings.bundle ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
fi
6 修改Setting
6.1 開發(fā)環(huán)境設(shè)置
修改Release
文件加下的.plist
文件 :
選中edit scheme
, 切換Build Configuration
:
運(yùn)行XCode, 在模擬器上查看 Setting
:
6.1 預(yù)發(fā)布環(huán)境設(shè)置
修改Staging
文件加下的.plist
文件 :
選中edit scheme
, 切換Build Configuration
:
運(yùn)行XCode, 在模擬器上查看 Setting
:
note: 由于開發(fā)環(huán)境我們沒有添加相應(yīng)腳本, 所以在Production
下運(yùn)行app, 是沒有Setting
的
參考
Adding a settings bundle to an iPhone App