React Native 03:換膚支持

因為原生這邊有個換膚功能,用戶下載對應(yīng)的皮膚包,app會重新渲染一些頁面元素色值贱鄙,以及替換相關(guān)圖片。某一天產(chǎn)品跑來說姨谷,RN的頁面也要支持換膚哦逗宁。雖然我默默的從抽屜里拿出來一把caidao。但還是要去想辦法把它搞掉梦湘。


思路如下:

1.先去看看原生那邊換膚是怎么玩的瞎颗。
  • 點開app下載一個皮膚包。會從服務(wù)器請求一個zip壓縮包捌议。
  • 解壓縮打開哼拔,一份色值表配置json文件,若干替換圖片瓣颅。

看代碼倦逐。大致實現(xiàn)是換膚庫提供了很多的UIKit組件的分類,提供了相關(guān)設(shè)置色值宫补,圖片的方法檬姥。并且會去注冊監(jiān)聽換膚通知。一般我們寫業(yè)務(wù)代碼的時候粉怕,都會使用那些分類所提供的支持換膚的方法健民。并且部分頁面需要主動監(jiān)聽換膚通知的從而實現(xiàn)主動渲染。當(dāng)觸發(fā)換膚的時候贫贝,頁面重新渲染荞雏,就會從對應(yīng)的皮膚包里獲取對應(yīng)的圖片,以及色值。從而實現(xiàn)的換膚凤优。

2.RN這邊既然要支持換膚悦陋,不就是JS中設(shè)置圖片,色值的地方改成通過橋接從原生那邊獲取對應(yīng)的色值和圖片嗎筑辨?
  • 色值
    首先原生寫好了一個橋接方法俺驶,傳入不同的key去色值表中查找對應(yīng)的16進制色值,返回給rn棍辕。rn頁面在render()函數(shù)之前暮现,調(diào)用該橋接獲取色值,并且通過state保存該色值楚昭。之后在render()函數(shù)渲染的時候設(shè)置到對應(yīng)的節(jié)點上就行了塘幅。好吧尿贫。是可以。后來又發(fā)現(xiàn)了個問題匾乓。RN中原生和JS橋接是異步執(zhí)行,那么就不能保證在render()函數(shù)執(zhí)行之前獲取到的是真正的色值咧七。很尷尬。這種方式好像行不通穴翩。換個思路。
  • 圖片
    其實RN加載圖片背蟆,是通過RCTImageLoader這個類志珍。通過斷點發(fā)現(xiàn)主要調(diào)用下面的那個方法。
-(RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest *)request
                                                             size:(CGSize)size
                                                            scale:(CGFloat)scale
                                                       resizeMode:(RCTResizeMode)resizeMode
                                                    progressBlock:(RCTImageLoaderProgressBlock)progressHandler
                                                 partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
                                                  completionBlock:(void (^)(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate))completionBlock {
}

主要的一個參數(shù)就是request。如果是網(wǎng)絡(luò)圖片就是正常的http:// 協(xié)議的鏈接淤翔。如果是本地圖片,不管是項目image.xcassets里的圖片還是mainBundle里的圖片寡具,又或者是沙盒里的圖片框喳,都會是一個file://協(xié)議的圖片本地地址乍惊。好吧。替換下圖片路徑試試莉撇?結(jié)果可行。那么RN圖片換膚就可以通過修改源碼來實現(xiàn)励翼。

3.圖片搞定了,還有色值呢殊橙?既然圖片可以通過修改源碼的形式搞定季研,那么色值能不能也通過修改源碼的方式去搞惹谐?找到原生這邊生成UIColor的方法?之前RN那部分不僅支持16進制的色值,而且還支持字符串類型的色值恳守,例如設(shè)置'red',RN最終會設(shè)置成真正的色值缎罢。RN是不是通過這個字符串key伊群,去它自己的色值表去查找對應(yīng)色值的呢?那么就要找到將‘red’解析成真正色值的方法舰始。
  • 原生部分
    找了半天蛮寂,發(fā)現(xiàn)了RCTConvert中有個方法是用來轉(zhuǎn)換顏色的及老。斷點發(fā)現(xiàn)RN中的設(shè)置顏色最終都會來到該方法里轉(zhuǎn)換成UIColor的對象僧鲁。
  + (UIColor *)UIColor:(id)json
{
  if (!json) {
    return nil;
  }
  if ([json isKindOfClass:[NSString class]]) {
      //去皮膚包查找色值
      if([json isEqualToString:@"ck_black"]) {
          return [UIColor whiteColor];
      }
  }
  if ([json isKindOfClass:[NSArray class]]) {
    NSArray *components = [self NSNumberArray:json];
    CGFloat alpha = components.count > 3 ? [self CGFloat:components[3]] : 1.0;
    return [UIColor colorWithRed:[self CGFloat:components[0]]
                           green:[self CGFloat:components[1]]
                            blue:[self CGFloat:components[2]]
                           alpha:alpha];
  } else if ([json isKindOfClass:[NSNumber class]]) {
    NSUInteger argb = [self NSUInteger:json];
    CGFloat a = ((argb >> 24) & 0xFF) / 255.0;
    CGFloat r = ((argb >> 16) & 0xFF) / 255.0;
    CGFloat g = ((argb >> 8) & 0xFF) / 255.0;
    CGFloat b = (argb & 0xFF) / 255.0;
    return [UIColor colorWithRed:r green:g blue:b alpha:a];
  } else {
    RCTLogConvertError(json, @"a UIColor. Did you forget to call processColor() on the JS side?");
    return nil;
  }
}

好吧朗涩。看起來該方法里只支持從RN那邊傳遞過來的NSArray類型和NSNumber類型的绑改。也不支持NSString類型的啊识腿。所以RN中通過'red'這種字符串設(shè)置顏色的解析并不是在原生這部分。所以在原生部分支持字符串類型造壮。通過該字符串key去對應(yīng)皮膚包的色值表中去查找真正的色值渡讼。

  • RN部分
    發(fā)現(xiàn)node_modules/react-native/Libraries/StyleSheet/processColor.js該文件中processColor()函數(shù)是用來解析色值的。
  var Platform = require('Platform');
  var normalizeColor = require('normalizeColor');
/* eslint no-bitwise: 0 */
function processColor(color) {
  if (color === undefined || color === null) {
    return color;
  }

  var int32Color = normalizeColor(color);
  if (int32Color === null) {
    return undefined;
  }

  if(typeof int32Color === 'string') {
    return int32Color;
  }

  // Converts 0xrrggbbaa into 0xaarrggbb
  int32Color = (int32Color << 24 | int32Color >>> 8) >>> 0;

  if (Platform.OS === 'android') {
    // Android use 32 bit *signed* integer to represent the color
    // We utilize the fact that bitwise operations in JS also operates on
    // signed 32 bit integers, so that we can use those to convert from
    // *unsigned* to *signed* 32bit int that way.
    int32Color = int32Color | 0x0;
  }
  return int32Color;
}

在該方法中费薄,RN會去查找類似'red'這樣的色值硝全,并且返回為一個32位int類型栖雾。如果沒找到對應(yīng)色值楞抡,它會強轉(zhuǎn)為一個0x0的色值。所以我們在它查找完之后析藕,強轉(zhuǎn)之前召廷,如果沒找到,直接將字符串類型的變量返回出去账胧,這樣原生也就能接受到一個字符串類型的key了竞慢。

最后

最后RN換膚實踐成功實現(xiàn)了產(chǎn)品的需求。就是找代碼的過程很藍(lán)瘦治泥,尤其是JS的那部分筹煮。如果RN版本升級了,動過的源碼部分也要同步過去居夹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末败潦,一起剝皮案震驚了整個濱河市本冲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌劫扒,老刑警劉巖檬洞,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異沟饥,居然都是意外死亡添怔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門贤旷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來广料,“玉大人,你說我怎么就攤上這事幼驶⌒哉眩” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵县遣,是天一觀的道長糜颠。 經(jīng)常有香客問我,道長萧求,這世上最難降的妖魔是什么其兴? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮夸政,結(jié)果婚禮上元旬,老公的妹妹穿的比我還像新娘。我一直安慰自己守问,他們只是感情好匀归,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著耗帕,像睡著了一般穆端。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上仿便,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天体啰,我揣著相機與錄音,去河邊找鬼嗽仪。 笑死荒勇,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的闻坚。 我是一名探鬼主播沽翔,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼窿凤!你這毒婦竟也來了仅偎?” 一聲冷哼從身側(cè)響起西潘,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎哨颂,沒想到半個月后喷市,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡威恼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年品姓,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箫措。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡腹备,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出斤蔓,到底是詐尸還是另有隱情植酥,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布弦牡,位于F島的核電站友驮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏驾锰。R本人自食惡果不足惜卸留,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望椭豫。 院中可真熱鬧耻瑟,春花似錦、人聲如沸赏酥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽裸扶。三九已至框都,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間姓言,已是汗流浹背瞬项。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留何荚,地道東北人。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓猪杭,卻偏偏與公主長得像餐塘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子皂吮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容