亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android 解決游戲發(fā)行切包資源索引沖突的問(wèn)題

 更新時(shí)間:2021年03月15日 09:40:28   作者:37手游團(tuán)隊(duì)  
這篇文章主要介紹了Android 解決游戲發(fā)行切包資源索引沖突的問(wèn)題,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下

背景

游戲發(fā)行切包過(guò)程中,經(jīng)常碰到渠道、研發(fā)、發(fā)行方,三方資源在合并過(guò)程中,資源ID沖突導(dǎo)致程序異常的問(wèn)題,此類問(wèn)題通過(guò)getIdentifier方式規(guī)避或者修改沖突資源ID的方式可以處理,但成本較高,本文旨在提出一種在切包過(guò)程中自動(dòng)化處理資源沖突的解決方案

1、public.xml介紹

1、public.xml這個(gè)文件是哪來(lái)的?

該文件是apktool在反編譯apk時(shí),根據(jù)apk包中的resources.arsc文件生成。

沒(méi)看過(guò)resource.arsc? (自己拖個(gè)apk到IDE看吧)

2、public.xml有什么作用

publc.xml是aapt在打包資源時(shí)用來(lái)固定資源id的,如果資源在public.xml中有對(duì)應(yīng)的id了,那么打包資源時(shí)就用已經(jīng)有的id。

3、public.xml中的id的格式

共四個(gè)字節(jié)32位,第一個(gè)字節(jié)代表PackgeID,第二個(gè)字節(jié)代表TypeID,后兩個(gè)字節(jié)代表資源值

通常系統(tǒng)資源PackageID是01,而我們自己的資源PackageID是7f

TypeID,比如attr為01,string為02。但是并不固定,并不一定attr就是01。但是在public.xml中,同類型的該字節(jié)一定是一樣的,否則回編譯會(huì)失敗。

2、R類介紹

R類這里有個(gè)知識(shí)點(diǎn),library模塊中生成的R類中的成員的值不是常量,不帶final。app模塊生成的R類的值是常量值。而常量值在java編譯時(shí)會(huì)被優(yōu)化,最終代碼中輸出的就是常量值,而不是R.id.xxx這樣。而library的因?yàn)槭亲兞?,不?huì)被優(yōu)化,代碼中會(huì)保留R.id.xxx

R類和public.xml的關(guān)系

從本質(zhì)上講,其實(shí)并沒(méi)有啥關(guān)系。但是由于在代碼中我們會(huì)使用R.id去查找資源,這就關(guān)聯(lián)上了。如果都用getIdentifier的方式先獲取id,那把R類刪了也沒(méi)事。

public.xml打包后對(duì)應(yīng)的就是resources.arsc中的值,而資源值生成Java類,這個(gè)類就是R類。也就是說(shuō)平時(shí)使用R類,就是用里面的索引值去到resources.arsc中找到對(duì)應(yīng)資源位置,再去加載。

3、切包融合過(guò)程中R類和public.xml的處理

切包過(guò)程中,R類屬于代碼,采用直接覆蓋的方式,但是由于我們生成的R類跟母包的R類其實(shí)值會(huì)是不同的。

下文中的cp指游戲研發(fā)方,即我們的SDK的接入方。

而public.xml是用的cp的,為什么用cp的?因?yàn)閏p建立的是app工程,R類是常量值,如果我們把母包中public.xml中已有的值給改了,萬(wàn)一母包中用了,那就gg了

由于R類在library中使用的時(shí)候是個(gè)變量,保留了R.id.xxx這種形式,解決方法就有了,糾正R類中的值跟public.xml對(duì)應(yīng),這樣就能繼續(xù)愉快的使用R.id.xxx了。

我們的切包過(guò)程有幾個(gè)步驟:

反編譯母包(指接入我們SDK的乙方)====》合并渠道資源====》合并入新sdk的資源(跳過(guò)研發(fā)更新我們的sdk的過(guò)程哈)

1、在反編譯母包的時(shí)候解析public.xml的值,存下來(lái)。

private void init() {
  List<Element> elements = mDocument.getRootElement().elements();
  for (Element element : elements) {
   String type = element.attribute(TYPE).getStringValue();
   String name = element.attribute(NAME).getStringValue();
   String id = element.attribute(ID).getStringValue();
   Map<String, String> typeMap = mTypeMap.get(type);
   if (typeMap == null) {
    typeMap = new HashMap<>();
    typeMap.put(name, id);
    mTypeMap.put(type, typeMap);
   } else {
    typeMap.put(name, id);
   }
  }
}

2、合并渠道資源的時(shí)候,將渠道資源中的public.xml(以channelPublic代指)合并到母包的public.xml(以matrixPublic代指)中

合并策略:

a、channelPublic中有,而matrixPublic中沒(méi)有,增加到matrixPublic中

比如增加如下數(shù)據(jù)到matrixPublic中

<public type="attr" name="iconSrc" id="0x7f0200a8" />

如果該type在matrixPublic中已經(jīng)存在:

首先要獲取到attr在matrixPublic中的PackageId+TypeId。在一個(gè)public.xml文件中,同類型比如attr對(duì)應(yīng)的PackageId+TypeId是不能變的,否則回編譯失敗。因此要添加數(shù)據(jù)時(shí),數(shù)據(jù)的PackageId+TypeId需要糾正為matrixPublic的值。

其次資源值,不能和已有的資源值重復(fù),正常情況下public.xml中的值是aapt生成的有序的,這里可以掃描matrixPublic中attr類型值的最大值,然后加一作為新加的iconSrc的id值

如果該type在matrixPublic中不存在(假設(shè)母包中matrixPublic中不存在attr類型)

首先要獲取類型已經(jīng)被占用的有哪些,即獲取到matrixPublic中的TypeId,正常情況也是有序的,獲取出最大的TypeId,加一作為新Type的起始值。賦值給iconSrc的id值

b、channelPublic中有,而matrixPublic中也有的,不需要處理,保留matrixPublic中的值不變

3、合并入新sdk的資源,在覆蓋完R類,后開(kāi)始糾正R類的值

掃描R類在PublicAndRHelper中

掃描覆蓋完R類的smali代碼中所有的R類,R$styleable類除外,因?yàn)閟tyleable中保存的是一些數(shù)組的值,規(guī)則不同。

/**
  * 掃描代碼中的R類
  * @return
  */
 private void scannerRClass(String path) {
  File smaliFilePath = new File(path);
  for (File file : smaliFilePath.listFiles()) {
   if (file.isDirectory()) {
    scannerRClass(file.getAbsolutePath());
   } else if(file.isFile()){
    if (file.getName().equals("R.smali") || file.getName().startsWith("R$")) {
     //此處過(guò)濾掉styleable文件
     if (!file.getName().endsWith("R$styleable.smali")) {
      mRClassFileList.add(file.getAbsolutePath());
     }
    }
   }
  }
 }

針對(duì)每一個(gè)R類調(diào)用糾正R類中方法,糾正R類值在RValueHelper類中

策略:匹配出要糾正的行,獲取到type,name。在public.xml中找出對(duì)應(yīng)的值,糾正。

注意這里的糾正不要用replace(oldValue,newValue)這種方式,要用替換行的方式,因?yàn)榇嬖谛轮翟赗類中也存在后,后續(xù)替換出問(wèn)題。比如a替換成b,b替換成c的情況最終R類中的a和b都被替換成了c

其次是styleable的處理,當(dāng)掃描到的R是attr類型的時(shí)候,判斷是否有styleable類型的存在,如果存在,則緩存下來(lái)attr中所做的糾正,用于糾正styleable。

public static void handle(String RFilePath, PublicXmlBean publicXmlBean) {
  File RFile = new File(RFilePath);
  String RStyleFilePath = "";
  Map<String, String> cacheMap = null;
  if (RFile.getName().endsWith("R$attr.smali")) {
   RStyleFilePath = RFilePath.replace("R$attr", "R$styleable");
   File RStyleAbleFile = new File(RStyleFilePath);
   //styleable存在,則把a(bǔ)ttr文件替換過(guò)的值緩存
   if (RStyleAbleFile.exists()) {
    cacheMap = new HashMap<>();
   }
  }
  String rFileContent = FileUtil.read(RFilePath);
  //找到RFile中是屬性的每一行
  ArrayList<String> lines = FileUtil.readAllLines(RFilePath, ".field public static final");
  String regex = ".field public static final (.*):(.*) = (.*)";
  for (String line : lines) {
   Pattern pattern = Pattern.compile(regex);
   Matcher matcher = pattern.matcher(line);
   if (matcher.find()) {
    String type = RFile.getName().replace("R$", "").replace(".smali", "");
    String name = matcher.group(1);
    String resetValue = publicXmlBean.getValue(type, name);
    if (StringUtils.isEmpty(resetValue)) {
     resetValue = publicXmlBean.addValue(type, matcher.group(1));
    }
    //替換到文件內(nèi)容中
    rFileContent = rFileContent.replace(line, ".field public static final " + name + ":" + matcher.group(2) + " = " + resetValue);
    if (cacheMap != null) {
     //換過(guò)的值緩存起來(lái)
     cacheMap.put(matcher.group(3), resetValue);
    }
   }
  }
  FileUtil.write(RFilePath, rFileContent);
  if (cacheMap != null) {
   //糾正R$styleable的值
   List<String> styleAbleLines = FileUtil.readAllLines(RStyleFilePath);
   BufferedWriter bw = null;
   try {
    bw = new BufferedWriter(new FileWriter(RStyleFilePath));
    for (String styleAbleLine : styleAbleLines) {
     for (String key : cacheMap.keySet()) {
      if (styleAbleLine.contains(key)) {
       styleAbleLine = styleAbleLine.replace(key, cacheMap.get(key));
      }
     }
     bw.write(styleAbleLine);
     bw.newLine();
    }
   } catch (IOException e) {
    e.printStackTrace();
   } finally {
    if (bw != null) {
     try {
      bw.close();
     } catch (IOException e) {
      bw = null;
     }
    }
   }
  }
 }

至此,糾正完了R類和public.xml的值

4、小結(jié)

游戲發(fā)行行業(yè)中,切包過(guò)程由于是多方代碼資源的一個(gè)合并過(guò)程,經(jīng)常出現(xiàn)資源沖突問(wèn)題。本方案致力于優(yōu)化切包過(guò)程,自動(dòng)化地解決資源沖突問(wèn)題。本方案已申請(qǐng)專利,并在我們實(shí)際業(yè)務(wù)中使用并穩(wěn)定運(yùn)行

以上就是Android 解決游戲發(fā)行切包資源索引沖突的問(wèn)題的詳細(xì)內(nèi)容,更多關(guān)于Android 游戲發(fā)行切包資源索引沖突的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論