Android 解决资源id冲突

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Text;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //OptimizeValues();

            var path1 = @"public1.xml";
            var path2 = @"public2.xml";

            Resolve(path1, path2);
        }

        static Dictionary GetTypeDictionary(List resources)
        {
            var typeDictionary = new Dictionary();

            for (var i = 0; i < resources.Count; i++)
            {
                var resource = resources[i];

                if (typeDictionary.ContainsKey(resource.type))
                    continue;

                typeDictionary[resource.type] = resource.id.Substring(2, 4);
            }

            return typeDictionary;
        }

        static Dictionary GetTypeDictionary(List resources1, List resources2)
        {
            var typeDictionary1 = GetTypeDictionary(resources1);
            var typeDictionary2 = GetTypeDictionary(resources2);

            var max = 0;

            foreach (var item in typeDictionary1)
            {
                var id = Int32.Parse(item.Value, NumberStyles.AllowHexSpecifier);
                max = Math.Max(max, id);
            }

            var typeDictionary = new Dictionary(typeDictionary1);
            foreach(var item in typeDictionary2)
            {
                if (typeDictionary.ContainsKey(item.Key))
                    continue;

                if (typeDictionary.ContainsValue(item.Value))
                {
                    max++;
                    typeDictionary[item.Key] = max.ToString("x4");
                }
                else
                {
                    typeDictionary[item.Key] = item.Value;
                    var id = Int32.Parse(item.Value, NumberStyles.AllowHexSpecifier);
                    max = Math.Max(max, id);
                }
            }

            return typeDictionary;
        }

        static void OptimizeValues(string[] files)
        {
            foreach (var path in files)
            {
                var lines = File.ReadAllLines(path);

                var contents = "";

                foreach (var line in lines)
                {
                    if (!line.Contains("APKTOOL_DUMMY_"))
                        contents += line + "\n";
                }

                File.WriteAllText(path, contents);
            }
        }

        static void Resolve(string path1, string path2)
        {
            var resources1 = XmlUtility.DeserializeXmlFromFile(path1).resources;
            var resources2 = XmlUtility.DeserializeXmlFromFile(path2).resources;

            var typeDictionary = GetTypeDictionary(resources1, resources2);

            var idDictionary = new Dictionary();

            for (var i = 0; i < resources2.Count; i++)
            {
                var resource = resources2[i];

                var old_id = resource.id;

                var type_id = typeDictionary[resource.type];
                resource.id = "0x" + type_id + resource.id.Substring(6);

                if (resource.id != old_id)
                    idDictionary[old_id] = resource.id;

                var item = resources1.Find(delegate (Resource r)
                {
                    return r.type == resource.type && r.name == resource.name && r.id == resource.id;
                });

                if (item != null)//完全相同
                    continue;

                var item1 = resources1.Find(delegate (Resource r)
                {
                    return r.id == resource.id;
                });

                var item2 = resources1.Find(delegate (Resource r)
                {
                    return r.type == resource.type && r.name == resource.name;
                });

                if (item1 == null && item2 == null)
                    continue;

                if (item1 != null && item2 == null)//id冲突,重新分配id
                {
                    var id = Int32.Parse(resource.id.Substring(2), NumberStyles.AllowHexSpecifier);
                    resource.id = "0x" + (id + 0x00007000).ToString("x8");
                    idDictionary[old_id] = resource.id;
                    continue;
                }

                resource.id = item2.id;
                idDictionary[old_id] = resource.id;
            }

            var smaliPath = @"smali";

            var files = Directory.GetFiles(smaliPath, "*", SearchOption.AllDirectories);

            foreach (var path in files)
            {
                var contents = File.ReadAllText(path);

                var count = 0;

                contents = Regex.Replace(contents, "(    const v[0-9]+, )(0x7f[0-9a-f]{6})", delegate (Match match)
                {
                    var old_id = match.Groups[2].Value;

                    var new_id = "";
                    if (!idDictionary.TryGetValue(old_id, out new_id))
                        return match.Groups[1].Value + old_id;

                    count++;

                    return match.Groups[1].Value + new_id;
                });

                //R文件常量
                contents = Regex.Replace(contents, "(.field public static final [a-zA-Z_][a-zA-Z0-9_]*:I = )(0x7f[0-9a-f]{6})", delegate (Match match)
                {
                    var old_id = match.Groups[2].Value;

                    var new_id = "";
                    if (!idDictionary.TryGetValue(old_id, out new_id))
                        return match.Groups[1].Value + old_id;

                    count++;

                    return match.Groups[1].Value + new_id;
                });

                if (count != 0)
                    File.WriteAllText(path, contents);
            }

            var resources = new Resources();
            resources.resources = resources2;
            XmlUtility.SerializeXmlToFile(path2, resources);
        }
    }

    [XmlType("resources")]
    public class Resources
    {
        [XmlElement("public")]
        public List resources;
    }

    public class Resource
    {
        [XmlAttribute]
        public string type;

        [XmlAttribute]
        public string name;

        [XmlAttribute]
        public string id;
    }

    public class Utf8StringWriter : StringWriter
    {
        public override Encoding Encoding
        {
            get
            {
                return Encoding.UTF8;
            }
        }
    }

    public class XmlUtility
    {
        public static T DeserializeXml(byte[] bytes)
        {
            T value = default(T);

            try
            {
                XmlSerializer deserializer = new XmlSerializer(typeof(T));

                using (MemoryStream memoryStream = new MemoryStream(bytes))
                {
                    TextReader textReader = new StreamReader(memoryStream);
                    value = (T)deserializer.Deserialize(textReader);
                    textReader.Close();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            return value;
        }

        public static T DeserializeXml(string text)
        {
            T value = default(T);

            try
            {
                XmlSerializer deserializer = new XmlSerializer(typeof(T));
                StringReader reader = new StringReader(text);
                value = (T)deserializer.Deserialize(reader);
                reader.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            return value;
        }

        public static T DeserializeXmlFromFile(string path)
        {
            if (!File.Exists(path))
                return default(T);

            string text = File.ReadAllText(path);

            return DeserializeXml(text);
        }

        public static string SerializeXml(object o)
        {
            string contents = null;

            try
            {
                XmlSerializer serializer = new XmlSerializer(o.GetType());
                using (StringWriter writer = new Utf8StringWriter())
                {
                    serializer.Serialize(writer, o);
                    contents = writer.ToString();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            return contents;
        }

        public static void SerializeXmlToFile(string path, object o)
        {
            if (string.IsNullOrEmpty(path))
                return;

            string contents = SerializeXml(o);
            if (contents != null)
                File.WriteAllText(path, contents);
        }
    }
}

你可能感兴趣的:(Android 解决资源id冲突)