.net 解析apk文件详解

1 篇文章 0 订阅
1 篇文章 0 订阅

公司临时分配了一个分发平台的项目,需要对上传的安装包进行解析安装包,并把数据存到数据库和七牛云,在此期间,我踩了非常多的坑,今天总结一下我踩了哪些坑。下面直接进入主题

1.首先我们要新建一个类库 ApkParser 我这里只做了apk的类库,ipa的以后有时间了再做

2.在类库下新建文件夹Zipper 后在此文件夹下添加UnzipApk 这个类,下面是代码

using System;
using System.IO;
using Ionic.Zip;

namespace APKParser.Zipper
{
    internal class UnzipApk
    {
        public void UnzipApkFile(String filePath)
        {
            try
            {
                var zipFileDirectory = Path.GetDirectoryName(filePath);
                var zipExtractFileDirectory = zipFileDirectory + "\\" + Path.GetFileNameWithoutExtension(filePath);

                // If exists then delete folder 
                if (Directory.Exists(zipExtractFileDirectory))
                {
                    Directory.Delete(zipExtractFileDirectory, true);
                }

                // Extract the zip
                using (ZipFile zip = ZipFile.Read(filePath))
                {
                    foreach (ZipEntry e in zip)
                    {
                        e.Extract(zipExtractFileDirectory, ExtractExistingFileAction.OverwriteSilently);
                    }
                }
            }
            catch (Exception x)
            {
                Console.WriteLine("Error in extracting the APK file, Please consider the below Message.");
                Console.WriteLine(x.StackTrace);
            }
        }
    }
}

3.然后再在类库下新建 APKInfo 这个类 下面是代码

using System;
using System.Collections.Generic;
using System.Globalization;

namespace ApkParser.Model
{
    public class ApkInfo
    {
        public static int FINE = 0;
        public static int NULL_VERSION_CODE = 1;
        public static int NULL_VERSION_NAME = 2;
        public static int NULL_PERMISSION = 3;
        public static int NULL_ICON = 4;
        public static int NULL_CERT_FILE = 5;
        public static int BAD_CERT = 6;
        public static int NULL_SF_FILE = 7;
        public static int BAD_SF = 8;
        public static int NULL_MANIFEST = 9;
        public static int NULL_RESOURCES = 10;
        public static int NULL_DEX = 13;
        public static int NULL_METAINFO = 14;
        public static int BAD_JAR = 11;
        public static int BAD_READ_INFO = 12;
        public static int NULL_FILE = 15;
        public static int HAS_REF = 16;


        public List<String> Permissions;
        public bool hasIcon;
        public List<String> iconFileName;
        public List<String> iconFileNameToGet;
        public List<String> iconHash;
        public String label;
        public Dictionary<String, String> layoutStrings;
        public String minSdkVersion;
        public String packageName;
        public Dictionary<String, List<String>> resStrings;
        public byte[] resourcesFileBytes;
        public String resourcesFileName;
        public bool supportAnyDensity;
        public bool supportLargeScreens;
        public bool supportNormalScreens;
        public bool supportSmallScreens;
        public String targetSdkVersion;
        public String versionCode;
        public String versionName;

        public ApkInfo()
        {
            hasIcon = false;
            supportSmallScreens = false;
            supportNormalScreens = false;
            supportLargeScreens = false;
            supportAnyDensity = true;
            versionCode = null;
            versionName = null;
            iconFileName = null;
            iconFileNameToGet = null;

            Permissions = new List<String>();
        }

        public static bool supportSmallScreen(byte[] dpi)
        {
            if (dpi[0] == 1)
                return true;
            return false;
        }

        public static bool supportNormalScreen(byte[] dpi)
        {
            if (dpi[1] == 1)
                return true;
            return false;
        }

        public static bool supportLargeScreen(byte[] dpi)
        {
            if (dpi[2] == 1)
                return true;
            return false;
        }

        //public byte[] getDPI()
        //{
        //    byte[] dpi = new byte[3];
        //    if (this.supportAnyDensity)
        //    {
        //        dpi[0] = 1;
        //        dpi[1] = 1;
        //        dpi[2] = 1;
        //    }
        //    else
        //    {
        //        if (this.supportSmallScreens)
        //            dpi[0] = 1;
        //        if (this.supportNormalScreens)
        //            dpi[1] = 1;
        //        if (this.supportLargeScreens)
        //            dpi[2] = 1;
        //    }
        //    return dpi;
        //}

        private bool isReference(List<String> strs)
        {
            try
            {
                foreach (String str in strs)
                {
                    if (isReference(str))
                        return true;
                }
            }
            catch (Exception e)
            {
                throw e;
            }
            return false;
        }

        private bool isReference(String str)
        {
            try
            {
                if (str != null && str.StartsWith("@"))
                {
                    int.Parse(str, NumberStyles.HexNumber);
                    return true;
                }
            }
            catch (Exception e)
            {
                throw e;
            }
            return false;
        }
    }
}

4.再在类库里添加APKManifest 这个类  下面是代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace APKParser
{
    public class ApkManifest
    {
        private string _result = "";
        // decompressXML -- Parse the 'compressed' binary form of Android XML docs 
        // such as for AndroidManifest.xml in .apk files
        public static int EndDocTag = 0x00100101;
        public static int StartTag = 0x00100102;
        public static int EndTag = 0x00100103;
        public string ReadManifestFileIntoXml(byte[] manifestFileData)
        {
            if (manifestFileData.Length == 0)
                throw new Exception("Failed to read manifest data.  Byte array was empty");
            // Compressed XML file/bytes starts with 24x bytes of data,
            // 9 32 bit words in little endian order (LSB first):
            //   0th word is 03 00 08 00
            //   3rd word SEEMS TO BE:  Offset at then of StringTable
            //   4th word is: Number of strings in string table
            // WARNING: Sometime I indiscriminently display or refer to word in 
            //   little endian storage format, or in integer format (ie MSB first).
            int numbStrings = LEW(manifestFileData, 4 * 4);

            // StringIndexTable starts at offset 24x, an array of 32 bit LE offsets
            // of the length/string data in the StringTable.
            int sitOff = 0x24;  // Offset of start of StringIndexTable

            // StringTable, each string is represented with a 16 bit little endian 
            // character count, followed by that number of 16 bit (LE) (Unicode) chars.
            int stOff = sitOff + numbStrings * 4;  // StringTable follows StrIndexTable

            // XMLTags, The XML tag tree starts after some unknown content after the
            // StringTable.  There is some unknown data after the StringTable, scan
            // forward from this point to the flag for the start of an XML start tag.
            int xmlTagOff = LEW(manifestFileData, 3 * 4);  // Start from the offset in the 3rd word.
            // Scan forward until we find the bytes: 0x02011000(x00100102 in normal int)
            for (int ii = xmlTagOff; ii < manifestFileData.Length - 4; ii += 4)
            {
                if (LEW(manifestFileData, ii) == StartTag)
                {
                    xmlTagOff = ii; break;
                }
            } // end of hack, scanning for start of first start tag

            // XML tags and attributes:
            // Every XML start and end tag consists of 6 32 bit words:
            //   0th word: 02011000 for startTag and 03011000 for endTag 
            //   1st word: a flag?, like 38000000
            //   2nd word: Line of where this tag appeared in the original source file
            //   3rd word: FFFFFFFF ??
            //   4th word: StringIndex of NameSpace name, or FFFFFFFF for default NS
            //   5th word: StringIndex of Element Name
            //   (Note: 01011000 in 0th word means end of XML document, endDocTag)

            // Start tags (not end tags) contain 3 more words:
            //   6th word: 14001400 meaning?? 
            //   7th word: Number of Attributes that follow this tag(follow word 8th)
            //   8th word: 00000000 meaning??

            // Attributes consist of 5 words: 
            //   0th word: StringIndex of Attribute Name's Namespace, or FFFFFFFF
            //   1st word: StringIndex of Attribute Name
            //   2nd word: StringIndex of Attribute Value, or FFFFFFF if ResourceId used
            //   3rd word: Flags?
            //   4th word: str ind of attr value again, or ResourceId of value

            // TMP, dump string table to tr for debugging
            //tr.addSelect("strings", null);
            //for (int ii=0; ii<numbStrings; ii++) {
            //  // Length of string starts at StringTable plus offset in StrIndTable
            //  String str = compXmlString(xml, sitOff, stOff, ii);
            //  tr.add(String.valueOf(ii), str);
            //}
            //tr.parent();

            // Step through the XML tree element tags and attributes
            int off = xmlTagOff;
            int indent = 0;
            int startTagLineNo = -2;
            while (off < manifestFileData.Length)
            {
                int tag0 = LEW(manifestFileData, off);
                //int tag1 = LEW(manifestFileData, off+1*4);
                int lineNo = LEW(manifestFileData, off + 2 * 4);
                //int tag3 = LEW(manifestFileData, off+3*4);
                int nameNsSi = LEW(manifestFileData, off + 4 * 4);
                int nameSi = LEW(manifestFileData, off + 5 * 4);

                if (tag0 == StartTag)
                { // XML START TAG
                    int tag6 = LEW(manifestFileData, off + 6 * 4);  // Expected to be 14001400
                    int numbAttrs = LEW(manifestFileData, off + 7 * 4);  // Number of Attributes to follow
                    //int tag8 = LEW(manifestFileData, off+8*4);  // Expected to be 00000000
                    off += 9 * 4;  // Skip over 6+3 words of startTag data
                    String name = compXmlString(manifestFileData, sitOff, stOff, nameSi);
                    //tr.addSelect(name, null);
                    startTagLineNo = lineNo;

                    // Look for the Attributes

                    string sb = "";
                    for (int ii = 0; ii < numbAttrs; ii++)
                    {
                        int attrNameNsSi = LEW(manifestFileData, off);  // AttrName Namespace Str Ind, or FFFFFFFF
                        int attrNameSi = LEW(manifestFileData, off + 1 * 4);  // AttrName String Index
                        int attrValueSi = LEW(manifestFileData, off + 2 * 4); // AttrValue Str Ind, or FFFFFFFF
                        int attrFlags = LEW(manifestFileData, off + 3 * 4);
                        int attrResId = LEW(manifestFileData, off + 4 * 4);  // AttrValue ResourceId or dup AttrValue StrInd
                        off += 5 * 4;  // Skip over the 5 words of an attribute

                        String attrName = compXmlString(manifestFileData, sitOff, stOff, attrNameSi);
                        String attrValue = attrValueSi != -1
                          ? compXmlString(manifestFileData, sitOff, stOff, attrValueSi)
                          : /*"resourceID 0x" + */attrResId.ToString();
                        sb += " " + attrName + "=\"" + attrValue + "\"";
                        //tr.add(attrName, attrValue);
                    }
                    prtIndent(indent, "<" + name + sb + ">");
                    indent++;

                }
                else if (tag0 == EndTag)
                { // XML END TAG
                    indent--;
                    off += 6 * 4;  // Skip over 6 words of endTag data
                    String name = compXmlString(manifestFileData, sitOff, stOff, nameSi);
                    prtIndent(indent, "</" + name + ">  \r\n"/*+"(line " + startTagLineNo + "-" + lineNo + ")"*/);
                    //tr.parent();  // Step back up the NobTree

                }
                else if (tag0 == EndDocTag)
                {  // END OF XML DOC TAG
                    break;

                }
                else
                {
                    prt("  Unrecognized tag code '" + tag0.ToString("X")
                      + "' at offset " + off);
                    break;
                }
            } // end of while loop scanning tags and attributes of XML tree
            //prt("    end at offset " + off);


            return _result;
        } // end of decompressXML


        public String compXmlString(byte[] xml, int sitOff, int stOff, int strInd)
        {
            if (strInd < 0) return null;
            int strOff = stOff + LEW(xml, sitOff + strInd * 4);
            return compXmlStringAt(xml, strOff);
        }


        public static String spaces = "                                             ";
        public void prtIndent(int indent, String str)
        {
            prt(spaces.Substring(0, Math.Min(indent * 2, spaces.Length)) + str);
        }

        private void prt(string p)
        {
            _result += p;
        }


        // compXmlStringAt -- Return the string stored in StringTable format at
        // offset strOff.  This offset points to the 16 bit string length, which 
        // is followed by that number of 16 bit (Unicode) chars.
        public String compXmlStringAt(byte[] arr, int strOff)
        {
            int strLen = arr[strOff + 1] << 8 & 0xff00 | arr[strOff] & 0xff;
            byte[] chars = new byte[strLen];
            for (int ii = 0; ii < strLen; ii++)
            {
                chars[ii] = arr[strOff + 2 + ii * 2];
            }


            return System.Text.Encoding.UTF8.GetString(chars);  // Hack, just use 8 byte chars
        } // end of compXmlStringAt


        // LEW -- Return value of a Little Endian 32 bit word from the byte array
        //   at offset off.
        public int LEW(byte[] arr, int off)
        {
            //return (int)(arr[off + 3] << 24 & 0xff000000 | arr[off + 2] << 16 & 0xff0000 | arr[off + 1] << 8 & 0xff00 | arr[off] & 0xFF);
            return (int)(((uint)arr[off + 3]) << 24 & 0xff000000 | ((uint)arr[off + 2]) << 16 & 0xff0000 | ((uint)arr[off + 1]) << 8 & 0xff00 | ((uint)arr[off]) & 0xFF);

        } // end of LEW

    }

}

5.再在类库里添加ApkReader  这个类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Diagnostics;
using ApkParser.Model;
using ApkParser;

namespace APKParser
{
    public class ApkReader
    {
        //private static Logger log = Logger.getLogger("APKReader");

        private const int VER_ID = 0;
        private const int ICN_ID = 1;
        private const int LABEL_ID = 2;
        String[] VER_ICN = new String[3];

        // Some possible tags and attributes
        String[] TAGS = { "manifest", "application", "activity" };
        String[] ATTRS = { "android:", "a:", "activity:", "_:" };

        Dictionary<String, object> entryList = new Dictionary<String, object>();

        List<String> tmpFiles = new List<String>();

        public String fuzzFindInDocument(XmlDocument doc, String tag, String attr)
        {
            foreach (String t in TAGS)
            {
                XmlNodeList nodelist = doc.GetElementsByTagName(t);
                for (int i = 0; i < nodelist.Count; i++)
                {
                    XmlNode element = (XmlNode)nodelist.Item(i);
                    if (element.NodeType == XmlNodeType.Element)
                    {
                        XmlAttributeCollection map = element.Attributes;
                        for (int j = 0; j < map.Count; j++)
                        {
                            XmlNode element2 = map.Item(j);
                            if (element2.Name.EndsWith(attr))
                            {
                                return element2.Value;
                            }
                        }
                    }
                }
            }
            return null;
        }


        private XmlDocument initDoc(String xml)
        {
            XmlDocument retval = new XmlDocument();
            retval.LoadXml(xml);
            retval.DocumentElement.Normalize();
            return retval;
        }


        private void extractPermissions(ApkInfo info, XmlDocument doc)
        {
            ExtractPermission(info, doc, "uses-permission", "name");
            ExtractPermission(info, doc, "permission-group", "name");
            ExtractPermission(info, doc, "service", "permission");
            ExtractPermission(info, doc, "provider", "permission");
            ExtractPermission(info, doc, "activity", "permission");
        }
        private bool readBoolean(XmlDocument doc, String tag, String attribute)
        {
            String str = FindInDocument(doc, tag, attribute);
            bool ret = false;
            try
            {
                ret = Convert.ToBoolean(str);
            }
            catch
            {
                ret = false;
            }
            return ret;
        }
        private void extractSupportScreens(ApkInfo info, XmlDocument doc)
        {
            info.supportSmallScreens = readBoolean(doc, "supports-screens", "android:smallScreens");
            info.supportNormalScreens = readBoolean(doc, "supports-screens", "android:normalScreens");
            info.supportLargeScreens = readBoolean(doc, "supports-screens", "android:largeScreens");

            if (info.supportSmallScreens || info.supportNormalScreens || info.supportLargeScreens)
                info.supportAnyDensity = false;
        }
        public ApkInfo ExtractInfo(byte[] manifest_xml, byte[] resources_arsx)
        {
            string manifestXml;
            var manifest = new ApkManifest();
            try
            {
                manifestXml = manifest.ReadManifestFileIntoXml(manifest_xml);
            }
            catch (Exception ex)
            {
                throw ex;
            }

            var doc = new XmlDocument();
            doc.LoadXml(manifestXml);
            return ExtractInfo(doc, resources_arsx);

        }
        public ApkInfo ExtractInfo(XmlDocument manifestXml, byte[] resources_arsx)
        {
            var info = new ApkInfo();
            VER_ICN[VER_ID] = "";
            VER_ICN[ICN_ID] = "";
            VER_ICN[LABEL_ID] = "";
            try
            {
                XmlDocument doc = manifestXml;
                if (doc == null)
                    throw new Exception("Document initialize failed");
                info.resourcesFileName = "resources.arsx";
                info.resourcesFileBytes = resources_arsx;
                // Fill up the permission field
                extractPermissions(info, doc);

                // Fill up some basic fields
                info.minSdkVersion = FindInDocument(doc, "uses-sdk", "minSdkVersion");
                info.targetSdkVersion = FindInDocument(doc, "uses-sdk", "targetSdkVersion");
                info.versionCode = FindInDocument(doc, "manifest", "versionCode");
                info.versionName = FindInDocument(doc, "manifest", "versionName");
                info.packageName = FindInDocument(doc, "manifest", "package");
                info.label = FindInDocument(doc, "application", "label");
                if (info.label.StartsWith("@"))
                    VER_ICN[LABEL_ID] = info.label;
                else
                    VER_ICN[LABEL_ID] = String.Format("@{0}", Convert.ToInt32(info.label).ToString("X4"));

                // Fill up the support screen field
                extractSupportScreens(info, doc);

                if (info.versionCode == null)
                    info.versionCode = fuzzFindInDocument(doc, "manifest",
                                    "versionCode");

                if (info.versionName == null)
                    info.versionName = fuzzFindInDocument(doc, "manifest",
                                    "versionName");
                else if (info.versionName.StartsWith("@"))
                    VER_ICN[VER_ID] = info.versionName;

                String id = FindInDocument(doc, "application", "android:icon");
                if (null == id)
                {
                    id = fuzzFindInDocument(doc, "manifest", "icon");
                }

                if (null == id)
                {
                    Debug.WriteLine("icon resId Not Found!");
                    return info;
                }

                // Find real strings
                if (!info.hasIcon)
                {
                    if (id.StartsWith("@android:"))
                        VER_ICN[ICN_ID] = "@"
                                        + (id.Substring("@android:".Length));
                    else
                        VER_ICN[ICN_ID] = String.Format("@{0}", Convert.ToInt32(id).ToString("X4"));

                    var resId = new List<String>();

                    for(int i = 0; i < VER_ICN.Length; i++)
                    {
                        if (VER_ICN[i].StartsWith("@"))
                            resId.Add(VER_ICN[i]);
                    }

                    var finder = new ApkResourceFinder();
                    info.resStrings = finder.processResourceTable(info.resourcesFileBytes, resId);

                    if (!VER_ICN[VER_ID].Equals(""))
                    {
                        List<String> versions = null;
                        if (info.resStrings.ContainsKey(VER_ICN[VER_ID].ToUpper()))
                            versions = info.resStrings[VER_ICN[VER_ID].ToUpper()];
                        if (versions != null)
                        {
                            if (versions.Count > 0)
                                info.versionName = versions[0];
                        }
                        else
                        {
                            throw new Exception(
                                            "VersionName Cant Find in resource with id "
                                                            + VER_ICN[VER_ID]);
                        }
                    }

                    List<String> iconPaths = null;
                    if (info.resStrings.ContainsKey(VER_ICN[ICN_ID].ToUpper()))
                        iconPaths = info.resStrings[VER_ICN[ICN_ID].ToUpper()];
                    if (iconPaths != null && iconPaths.Count > 0)
                    {
                        info.iconFileNameToGet = new List<String>();
                        info.iconFileName = new List<string>();
                        foreach (String iconFileName in iconPaths)
                        {
                            if (iconFileName != null)
                            {
                                if (iconFileName.Contains(@"/"))
                                {
                                    info.iconFileNameToGet.Add(iconFileName);
                                    info.iconFileName.Add(iconFileName);
                                    info.hasIcon = true;
                                }
                            }
                        }
                    }
                    else
                    {
                        throw new Exception("Icon Cant Find in resource with id "
                                        + VER_ICN[ICN_ID]);
                    }

                    if (!VER_ICN[LABEL_ID].Equals(""))
                    {
                        List<String> labels = null;
                        if (info.resStrings.ContainsKey(VER_ICN[LABEL_ID]))
                            labels = info.resStrings[VER_ICN[LABEL_ID]];
                        if (labels != null && labels.Count > 0)
                        {
                            info.label = labels[0];
                        }
                    }
                }

            }
            catch (Exception e)
            {
                throw e;
            }
            return info;
        }




        private void ExtractPermission(ApkInfo info, XmlDocument doc, String keyName, String attribName)
        {
            XmlNodeList usesPermissions = doc.GetElementsByTagName(keyName);
            if (usesPermissions != null)
            {
                for (int s = 0; s < usesPermissions.Count; s++)
                {
                    XmlNode permissionNode = usesPermissions.Item(s);
                    if (permissionNode != null && permissionNode.NodeType == XmlNodeType.Element)
                    {
                        XmlNode node = permissionNode.Attributes.GetNamedItem(attribName);
                        if (node != null)
                            info.Permissions.Add(node.Value);
                    }
                }
            }
        }
        private String FindInDocument(XmlDocument doc, String keyName,
                String attribName)
        {
            XmlNodeList usesPermissions = doc.GetElementsByTagName(keyName);

            if (usesPermissions != null)
            {
                for (int s = 0; s < usesPermissions.Count; s++)
                {
                    XmlNode permissionNode = usesPermissions.Item(s);
                    if (permissionNode.NodeType == XmlNodeType.Element)
                    {
                        XmlNode node = permissionNode.Attributes.GetNamedItem(attribName);
                        if (node != null)
                            return node.Value;
                    }
                }
            }
            return null;
        }

    }
}

6.再在类库里添加ApkResourceFinder 这个类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace ApkParser
{
    public class ApkResourceFinder
    {
        private const long HEADER_START = 0;
        static short RES_STRING_POOL_TYPE = 0x0001;
        static short RES_TABLE_TYPE = 0x0002;
        static short RES_TABLE_PACKAGE_TYPE = 0x0200;
        static short RES_TABLE_TYPE_TYPE = 0x0201;
        static short RES_TABLE_TYPE_SPEC_TYPE = 0x0202;

        String[] valueStringPool = null;
        String[] typeStringPool = null;
        String[] keyStringPool = null;

        private int package_id = 0;
        private List<String> resIdList;

         Contains no data.
        //static byte TYPE_NULL = 0x00;
         The 'data' holds an attribute resource identifier.
        //static byte TYPE_ATTRIBUTE = 0x02;
         The 'data' holds a single-precision floating point number.
        //static byte TYPE_FLOAT = 0x04;
         The 'data' holds a complex number encoding a dimension value,
         such as "100in".
        //static byte TYPE_DIMENSION = 0x05;
         The 'data' holds a complex number encoding a fraction of a
         container.
        //static byte TYPE_FRACTION = 0x06;
         The 'data' is a raw integer value of the form n..n.
        //static byte TYPE_INT_DEC = 0x10;
         The 'data' is a raw integer value of the form 0xn..n.
        //static byte TYPE_INT_HEX = 0x11;
         The 'data' is either 0 or 1, for input "false" or "true" respectively.
        //static byte TYPE_INT_BOOLEAN = 0x12;
         The 'data' is a raw integer value of the form #aarrggbb.
        //static byte TYPE_INT_COLOR_ARGB8 = 0x1c;
         The 'data' is a raw integer value of the form #rrggbb.
        //static byte TYPE_INT_COLOR_RGB8 = 0x1d;
         The 'data' is a raw integer value of the form #argb.
        //static byte TYPE_INT_COLOR_ARGB4 = 0x1e;
         The 'data' is a raw integer value of the form #rgb.
        //static byte TYPE_INT_COLOR_RGB4 = 0x1f;

        // The 'data' holds a ResTable_ref, a reference to another resource
        // table entry.
        static byte TYPE_REFERENCE = 0x01;
        // The 'data' holds an index into the containing resource table's
        // global value string pool.
        static byte TYPE_STRING = 0x03;



        private Dictionary<String, List<String>> responseMap;

        Dictionary<int, List<String>> entryMap = new Dictionary<int, List<String>>();

        public Dictionary<string, List<String>> initialize()
        {
            byte[] data = System.IO.File.ReadAllBytes("resources.arsc");
            return this.processResourceTable(data, new List<string>());
        }
        public Dictionary<string, List<String>> processResourceTable(byte[] data, List<String> resIdList)
        {
            this.resIdList = resIdList;

            responseMap = new Dictionary<string, List<String>>();
            long lastPosition;

            using (MemoryStream ms = new MemoryStream(data))
            {

                using (BinaryReader br = new BinaryReader(ms))
                {

                    short type = br.ReadInt16();
                    short headerSize = br.ReadInt16();
                    int size = br.ReadInt32();
                    int packageCount = br.ReadInt32();


                    if (type != RES_TABLE_TYPE)
                    {
                        throw new Exception("No RES_TABLE_TYPE found!");
                    }
                    if (size != br.BaseStream.Length)
                    {
                        throw new Exception("The buffer size not matches to the resource table size.");
                    }

                    int realStringPoolCount = 0;
                    int realPackageCount = 0;


                    while (true)
                    {
                        long pos = br.BaseStream.Position;
                        short t = br.ReadInt16();
                        short hs = br.ReadInt16();
                        int s = br.ReadInt32();

                        if (t == RES_STRING_POOL_TYPE)
                        {
                            if (realStringPoolCount == 0)
                            {
                                // Only the first string pool is processed.
                                Debug.WriteLine("Processing the string pool ...");


                                byte[] buffer = new byte[s];
                                lastPosition = br.BaseStream.Position;
                                br.BaseStream.Seek(pos, SeekOrigin.Begin);
                                buffer = br.ReadBytes(s);
                                //br.BaseStream.Seek(lastPosition, SeekOrigin.Begin);

                                valueStringPool = processStringPool(buffer);

                            }
                            realStringPoolCount++;

                        }
                        else if (t == RES_TABLE_PACKAGE_TYPE)
                        {
                            // Process the package
                            Debug.WriteLine("Processing package {0} ...", realPackageCount);

                            byte[] buffer = new byte[s];
                            lastPosition = br.BaseStream.Position;
                            br.BaseStream.Seek(pos, SeekOrigin.Begin);
                            buffer = br.ReadBytes(s);
                            //br.BaseStream.Seek(lastPosition, SeekOrigin.Begin);
                            processPackage(buffer);

                            realPackageCount++;

                        }
                        else
                        {
                            throw new InvalidOperationException("Unsupported Type");
                        }
                        br.BaseStream.Seek(pos + (long)s, SeekOrigin.Begin);
                        if (br.BaseStream.Position == br.BaseStream.Length)
                            break;

                    }

                    if (realStringPoolCount != 1)
                    {
                        throw new Exception("More than 1 string pool found!");
                    }
                    if (realPackageCount != packageCount)
                    {
                        throw new Exception(
                                        "Real package count not equals the declared count.");
                    }

                    return responseMap;

                }
            }

        }

        private void processPackage(byte[] data)
        {
            long lastPosition = 0;
            using (MemoryStream ms = new MemoryStream(data))
            {

                using (BinaryReader br = new BinaryReader(ms))
                {
                    //HEADER
                    short type = br.ReadInt16();
                    short headerSize = br.ReadInt16();
                    int size = br.ReadInt32();

                    int id = br.ReadInt32();
                    package_id = id;

                    //PackageName
                    char[] name = new char[256];
                    for (int i = 0; i < 256; ++i)
                    {
                        name[i] = br.ReadChar();
                    }
                    int typeStrings = br.ReadInt32();
                    int lastPublicType = br.ReadInt32();
                    int keyStrings = br.ReadInt32();
                    int lastPublicKey = br.ReadInt32();

                    if (typeStrings != headerSize)
                    {
                        throw new Exception("TypeStrings must immediately follow the package structure header.");
                    }

                    Debug.WriteLine("Type strings:");
                    lastPosition = br.BaseStream.Position;
                    br.BaseStream.Seek(typeStrings, SeekOrigin.Begin);
                    byte[] bbTypeStrings = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position));
                    br.BaseStream.Seek(lastPosition, SeekOrigin.Begin);

                    typeStringPool = processStringPool(bbTypeStrings);

                    Debug.WriteLine("Key strings:");

                    br.BaseStream.Seek(keyStrings, SeekOrigin.Begin);
                    short key_type = br.ReadInt16();
                    short key_headerSize = br.ReadInt16();
                    int key_size = br.ReadInt32();

                    lastPosition = br.BaseStream.Position;
                    br.BaseStream.Seek(keyStrings, SeekOrigin.Begin);
                    byte[] bbKeyStrings = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position));
                    br.BaseStream.Seek(lastPosition, SeekOrigin.Begin);

                    keyStringPool = processStringPool(bbKeyStrings);



                    // Iterate through all chunks
                    //
                    int typeSpecCount = 0;
                    int typeCount = 0;

                    br.BaseStream.Seek((keyStrings + key_size), SeekOrigin.Begin);

                    while (true)
                    {
                        int pos = (int)br.BaseStream.Position;
                        short t = br.ReadInt16();
                        short hs = br.ReadInt16();
                        int s = br.ReadInt32();

                        if (t == RES_TABLE_TYPE_SPEC_TYPE)
                        {
                            // Process the string pool
                            byte[] buffer = new byte[s];
                            br.BaseStream.Seek(pos, SeekOrigin.Begin);
                            buffer = br.ReadBytes(s);

                            processTypeSpec(buffer);

                            typeSpecCount++;
                        }
                        else if (t == RES_TABLE_TYPE_TYPE)
                        {
                            // Process the package
                            byte[] buffer = new byte[s];
                            br.BaseStream.Seek(pos, SeekOrigin.Begin);
                            buffer = br.ReadBytes(s);

                            processType(buffer);

                            typeCount++;
                        }

                        br.BaseStream.Seek(pos + s, SeekOrigin.Begin);
                        if (br.BaseStream.Position == br.BaseStream.Length)
                            break;
                    }

                    return;

                }
            }

        }
        private void putIntoMap(String resId, String value)
        {
            List<String> valueList = null;
            if (responseMap.ContainsKey(resId.ToUpper()))
                valueList = responseMap[resId.ToUpper()];
            if (valueList == null)
            {
                valueList = new List<String>();
            }
            valueList.Add(value);
            if (responseMap.ContainsKey(resId.ToUpper()))
                responseMap[resId.ToUpper()] = valueList;
            else
                responseMap.Add(resId.ToUpper(), valueList);
            return;

        }

        private void processType(byte[] typeData)
        {
            using (MemoryStream ms = new MemoryStream(typeData))
            {
                using (BinaryReader br = new BinaryReader(ms))
                {
                    short type = br.ReadInt16();
                    short headerSize = br.ReadInt16();
                    int size = br.ReadInt32();
                    byte id = br.ReadByte();
                    byte res0 = br.ReadByte();
                    short res1 = br.ReadInt16();
                    int entryCount = br.ReadInt32();
                    int entriesStart = br.ReadInt32();

                    Dictionary<String, int> refKeys = new Dictionary<String, int>();

                    int config_size = br.ReadInt32();

                    // Skip the config data
                    br.BaseStream.Seek(headerSize, SeekOrigin.Begin);


                    if (headerSize + entryCount * 4 != entriesStart)
                    {
                        throw new Exception("HeaderSize, entryCount and entriesStart are not valid.");
                    }

                    // Start to get entry indices
                    int[] entryIndices = new int[entryCount];
                    for (int i = 0; i < entryCount; ++i)
                    {
                        entryIndices[i] = br.ReadInt32();
                    }

                    // Get entries
                    for (int i = 0; i < entryCount; ++i)
                    {
                        if (entryIndices[i] == -1)
                            continue;

                        int resource_id = (package_id << 24) | (id << 16) | i;

                        long pos = br.BaseStream.Position;
                        short entry_size = br.ReadInt16();
                        short entry_flag = br.ReadInt16();
                        int entry_key = br.ReadInt32();

                        // Get the value (simple) or map (complex)
                        int FLAG_COMPLEX = 0x0001;

                        if ((entry_flag & FLAG_COMPLEX) == 0)
                        {
                            // Simple case
                            short value_size = br.ReadInt16();
                            byte value_res0 = br.ReadByte();
                            byte value_dataType = br.ReadByte();
                            int value_data = br.ReadInt32();

                            String idStr = resource_id.ToString("X4");
                            String keyStr = keyStringPool[entry_key];
                            String data = null;

                            Debug.WriteLine("Entry 0x" + idStr + ", key: " + keyStr + ", simple value type: ");

                            List<String> entryArr = null;
                            if (entryMap.ContainsKey(int.Parse(idStr, System.Globalization.NumberStyles.HexNumber)))
                                entryArr = entryMap[int.Parse(idStr, System.Globalization.NumberStyles.HexNumber)];

                            if (entryArr == null)
                                entryArr = new List<String>();

                            entryArr.Add(keyStr);
                            if (entryMap.ContainsKey(int.Parse(idStr, System.Globalization.NumberStyles.HexNumber)))
                                entryMap[int.Parse(idStr, System.Globalization.NumberStyles.HexNumber)] = entryArr;
                            else
                                entryMap.Add(int.Parse(idStr, System.Globalization.NumberStyles.HexNumber), entryArr);

                            if (value_dataType == TYPE_STRING)
                            {
                                data = valueStringPool[value_data];
                                Debug.WriteLine(", data: " + valueStringPool[value_data] + "");
                            }
                            else if (value_dataType == TYPE_REFERENCE)
                            {
                                String hexIndex = value_data.ToString("X4");
                                refKeys.Add(idStr, value_data);
                            }
                            else
                            {
                                data = value_data.ToString();
                                Debug.WriteLine(", data: " + value_data + "");
                            }

                            // if (inReqList("@" + idStr)) {
                            putIntoMap("@" + idStr, data);
                        }
                        else
                        {
                            int entry_parent = br.ReadInt32();
                            int entry_count = br.ReadInt32();

                            for (int j = 0; j < entry_count; ++j)
                            {
                                int ref_name = br.ReadInt32();
                                short value_size = br.ReadInt16();
                                byte value_res0 = br.ReadByte();
                                byte value_dataType = br.ReadByte();
                                int value_data = br.ReadInt32();
                            }

                            Debug.WriteLine("Entry 0x"
                                                    + resource_id.ToString("X4") + ", key: "
                                                    + keyStringPool[entry_key]
                                                    + ", complex value, not printed.");
                        }

                    }
                    HashSet<String> refKs = new HashSet<String>(refKeys.Keys);

                    foreach (String refK in refKs)
                    {
                        List<String> values = null;
                        if (responseMap.ContainsKey("@" + refKeys[refK].ToString("X4").ToUpper()))
                            values = responseMap["@" + refKeys[refK].ToString("X4").ToUpper()];

                        if (values != null)
                            foreach (String value in values)
                            {
                                putIntoMap("@" + refK, value);
                            }
                    }
                    return;

                }
            }
        }



        private string[] processStringPool(byte[] data)
        {
            long lastPosition = 0;

            using (MemoryStream ms = new MemoryStream(data))
            {

                using (BinaryReader br = new BinaryReader(ms))
                {
                    short type = br.ReadInt16();
                    short headerSize = br.ReadInt16();
                    int size = br.ReadInt32();
                    int stringCount = br.ReadInt32();
                    int styleCount = br.ReadInt32();
                    int flags = br.ReadInt32();
                    int stringsStart = br.ReadInt32();
                    int stylesStart = br.ReadInt32();

                    bool isUTF_8 = (flags & 256) != 0;

                    int[] offsets = new int[stringCount];
                    for (int i = 0; i < stringCount; ++i)
                    {
                        offsets[i] = br.ReadInt32();
                    }
                    String[] strings = new String[stringCount];

                    for (int i = 0; i < stringCount; i++)
                    {
                        int pos = stringsStart + offsets[i];
                        lastPosition = br.BaseStream.Position;
                        short len = (short)br.BaseStream.Seek(pos, SeekOrigin.Begin);
                        br.BaseStream.Seek(lastPosition, SeekOrigin.Begin);

                        if (len < 0)
                        {
                            short extendShort = br.ReadInt16();
                        }
                        pos += 2;
                        strings[i] = "";
                        if (isUTF_8)
                        {
                            int start = pos;
                            int length = 0;
                            lastPosition = br.BaseStream.Position;
                            br.BaseStream.Seek(pos, SeekOrigin.Begin);
                            while (br.ReadByte() != 0)
                            {
                                length++;
                                pos++;
                            }
                            br.BaseStream.Seek(lastPosition, SeekOrigin.Begin);

                            byte[] oneData = new byte[length];
                            if (length > 0)
                            {
                                byte[] byteArray = data;
                                for (int k = 0; k < length; k++)
                                {
                                    oneData[k] = byteArray[start + k];
                                }
                            }
                            if (oneData.Length > 0)
                                strings[i] = Encoding.UTF8.GetString(oneData);
                            else
                                strings[i] = "";
                        }
                        else
                        {
                            char c;
                            lastPosition = br.BaseStream.Position;
                            br.BaseStream.Seek(pos, SeekOrigin.Begin);
                            while ((c = br.ReadChar()) != 0)
                            {
                                strings[i] += c;
                                pos += 2;
                            }
                            br.BaseStream.Seek(lastPosition, SeekOrigin.Begin);
                        }
                        Debug.WriteLine("Parsed value: {0}", strings[i]);


                    }
                    return strings;

                }
            }
        }

        private void processTypeSpec(byte[] data)
        {
            using (MemoryStream ms = new MemoryStream(data))
            {

                using (BinaryReader br = new BinaryReader(ms))
                {
                    short type = br.ReadInt16();
                    short headerSize = br.ReadInt16();
                    int size = br.ReadInt32();
                    byte id = br.ReadByte();
                    byte res0 = br.ReadByte();
                    short res1 = br.ReadInt16();
                    int entryCount = br.ReadInt32();


                    Debug.WriteLine("Processing type spec {0}", typeStringPool[id - 1]);

                    int[] flags = new int[entryCount];
                    for (int i = 0; i < entryCount; ++i)
                    {
                        flags[i] = br.ReadInt32();
                    }

                    return;
                }
            }
        }

    }
}

7.再在类库里添加ParseAPK 这个类 

using System;
using System.IO;
using ApkParser.Model;
using APKParser.Zipper;
using ApkParser;

namespace APKParser
{
    public class ParseApk
    {
        public ApkInfo ParseApkInfo(String filePath)
        {
            // Reading the APK File
            var apkReader = new ApkReader();

            //Unzipping the APK file to read the information from the APK file
            var unzipApk = new UnzipApk();
            unzipApk.UnzipApkFile(filePath);

            //Variables will store the binary data
            byte[] manifestData = null;
            byte[] resourcesData = null;

            // Looping through each and every sub directory in the extracted directory
            String zipExtractFileDirectory = Path.GetDirectoryName(filePath) + "\\" +
                                             Path.GetFileNameWithoutExtension(filePath);
            try
            {
                foreach (string file in Directory.GetFiles(zipExtractFileDirectory))
                {
                    var fileName = Path.GetFileName(file);

                    if (fileName != null && fileName.ToLower() == "androidmanifest.xml")
                    {
                        manifestData = new byte[50*1024];
                        using (var binaryStream = new BinaryReader(File.Open(file, FileMode.Open)))
                        {
                            manifestData = binaryStream.ReadBytes((int)binaryStream.BaseStream.Length);
                        }
                    }
                    else if (fileName != null && fileName.ToLower() == "resources.arsc")
                    {
                        using (var binaryStream = new BinaryReader(File.Open(file, FileMode.Open)))
                        {
                            resourcesData = binaryStream.ReadBytes((int)binaryStream.BaseStream.Length);
                        }
                    }
                }

                // Reading the manifest file and Resources file
                var apkInfo = apkReader.ExtractInfo(manifestData, resourcesData);
                return apkInfo;
            }
            catch (Exception excpt)
            {
                Console.WriteLine(excpt.Message);
                return null;
            }
        }
    }
}

下面给你们看一下这个类库的一些引用

 好   到这里我们的条件就这么好了。下面开始我们就实操  上代码

string url= Server.MapPath("/Areas/Distribute/File/");//服务器图片存储位置
            string saveurl = UploadLocal.LocalImage(HttpContext.Request.Files[0], url);  //这里我将文件保存到本地,返回其路径地址
            ApkInfo info = _applyList.GetApkInfo(saveurl);//这里就去使用我这个类库里的实际方法了,传入我存的文件路径 ,解析后返回我对应的安装包信息  这里很占用资源
            string icon = url + System.IO.Path.GetFileNameWithoutExtension(saveurl) + "/" + info.iconFileName[0];  //这个是解析后的应用图标路径
            icon = icon.Replace('/', '\\');//解决路径小毛病
            string Qicon = await _applyList.UploadIcon(icon);//这里通过路径上传图标到七牛云
            string Qurl = await _applyList.UploadData(saveurl);//这里上传安装包到七牛云
            UploadLocal.DeleteDir(url);//删除指定文件夹下面所有文件和文件夹

 下面那一节是我的业务操作就不展示了

我这里把存本地的方法也放出来

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace GenernalMVC.Common.Upload
{
    public class UploadLocal
    {
        /// <summary>
        /// 上传到服务器本地
        /// </summary>
        /// <param name="files">文件流</param>
        /// <param name="url">文件存到哪个文件夹</param>
        /// <returns></returns>
        public static string LocalImage(HttpPostedFileBase files, string url)
        {
            MemoryStream target = new MemoryStream();
            files.InputStream.CopyTo(target);
            if (files == null)
            {//判断是否空提交
                return null;
            }
            string name = UploadImage.Chars(6, true, "");
            string extension = Path.GetExtension(files.FileName).ToLower();
            string fileName = name + extension;
            string saveUrl = url + fileName;
            files.SaveAs(saveUrl);//保存文件
            return saveUrl;
        }
        #region 删除指定文件夹下的所有文件
        /// <summary>
        /// 删除指定文件夹下的所有文件
        /// </summary>
        /// <param name="strPath"></param>
        /// <returns></returns>
        public static bool DeleteDir(string strPath)
        {
            try
            {
                strPath = @strPath.Trim();
                if (Directory.Exists(strPath))
                {
                    string[] strDirs = Directory.GetDirectories(strPath);
                    string[] strFiles = Directory.GetFiles(strPath);
                    foreach (string strFile in strFiles)
                    {
                        File.Delete(strFile);
                    }
                    foreach (string strdir in strDirs)
                    {
                        Directory.Delete(strdir, true);
                    }
                }
                return true;
            }
            catch (Exception Exp)
            {
                System.Diagnostics.Debug.Write(Exp.Message);
                return false;
            }
        }
        #endregion

        public static double GetFileSize(HttpPostedFileBase files) 
        {
           return GetFileSize(files.ContentLength);
        }
        /// <summary>
        /// 格式化文件大小
        /// </summary>
        /// <param name="filesize">文件传入大小</param>
        /// <returns></returns>
        private static double GetFileSize(long filesize)
        {
            try
            {
                if (filesize < 0)
                {
                    return 0;
                }
                else {
                    return (double)filesize / (1024 * 1024);
                }
                /*else if (filesize >= 1024 * 1024 * 1024)  //文件大小大于或等于1024MB    
                {
                    return string.Format("{0:0.00} GB", (double)filesize / (1024 * 1024 * 1024));
                }
                else if (filesize >= 1024 * 1024) //文件大小大于或等于1024KB    
                {
                    return string.Format("{0:0.00} MB", (double)filesize / (1024 * 1024));
                }
                else if (filesize >= 1024) //文件大小大于等于1024bytes    
                {
                    return string.Format("{0:0.00} KB", (double)filesize / 1024);
                }
                else
                {
                    return string.Format("{0:0.00} bytes", filesize);
                }*/
            }
            catch (Exception ex)
            {

                throw ex;
            }

        }
    }
}

代码到这里我就不得不说我踩到的一个大坑,当时做的时候我解析apk和上传七牛云之间出现的一个bug,我花了两三天去解决这个问题,一开始我以为是代码问题然后去一步步调试,把这两个操作分开都没问题,但是放到一起就出问题了,把解析apk代码放到上传前面,七牛云就抱406,不可接受,第二次我把上传文件代码放到解析apk前面,然后解析apk代码就报读取不了这个压缩文件,就是这个apk文件。我也问了很多大佬,一些交流群里的大佬始终得不到正确的解决方法,后面我也去找了七牛云的技术支持,说406是七牛云的Crc32验证不通过,当时人都蒙了,C#里上传文件没有这个·验证Crc32验证,后面我翻七牛云的SDK文档,发现了一种通过字节流的上传操作,

后面换了这种上传方式居然又行了,还是我太年轻了,注我以前七牛云上传操作都是通过文件流的形式上传

我给你们上文件流上传代码和字节流上传代码

using Qiniu.Http;
using Qiniu.Storage;
using Qiniu.Util;
using System;
using System.Configuration;
using System.Globalization;
using System.IO;
using System.Threading.Tasks;
using System.Web;

namespace GenernalMVC.Common.Upload
{
    /*==================================================================
     *    类名    :   上传图片工具类
     *    功能    :   上传图片到七牛云
     *    作者    :   
     *    日期    :   20220706
     *    修改记录:
    /*==================================================================*/
    public class UploadImage
    {
        string AccessKey = ConfigurationManager.AppSettings["AccessKey"].ToString();
        string SecretKey = ConfigurationManager.AppSettings["SecretKey"].ToString();
        string QiniuAddress = ConfigurationManager.AppSettings["QiniuAddress"].ToString();
        string QiniuAppAddress= ConfigurationManager.AppSettings["QiniuAppAddress"].ToString();
        string bucket = "xdjofficial";//这个是我们在七牛云上创建的“存储空间”名称
        /// <summary>
        /// 通过文件流上传的七牛云,不存本地
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public async Task<string> Upload(HttpPostedFileBase file)
        {
            var newFileName = DateTime.Now.ToString("yyyyMMddHHmmss_fffff", DateTimeFormatInfo.InvariantInfo) + ".jpg";
            string saveKey = "xdjmvc/" + newFileName;
            //string saveKey = "xdjmvc/" + file.FileName; //这个myfile 相当于一个文件夹,是我们只设定的。2.png是我们上传文件的文件名,上传成功后通过它来读
            Mac mac = new Mac(AccessKey, SecretKey); // 生成(上传)凭证时需要使用此Mac
            PutPolicy putPolicy = new PutPolicy();
            // 如果需要设置为"覆盖"上传(如果云端已有同名文件则覆盖),请使用 SCOPE = "BUCKET:KEY"
            // putPolicy.Scope = bucket + ":" + saveKey;
            putPolicy.Scope = bucket;
            // 上传策略有效期(对应于生成的凭证的有效期)          
            putPolicy.SetExpires(3600);
            // 上传到云端多少天后自动删除该文件,如果不设置(即保持默认默认)则不删除
            //putPolicy.DeleteAfterDays = 1;
            putPolicy.ReturnBody = "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"fsiz\":$(fsize),\"bucket\":\"$(bucket)\",\"name\":\"$(x:name)\"}";
            // 生成上传凭证                    
            string token = Auth.CreateUploadToken(mac, putPolicy.ToJsonString());//token生成
            FormUploader target = new FormUploader(new Config() { Zone = Zone.ZoneCnSouth, UseHttps = true, UseCdnDomains = true, MaxRetryTimes = 3 });
            HttpResult result = await target.UploadStream(file.InputStream, saveKey, token,new PutExtra());
            QiniuModel model = new QiniuModel();
            model = result.Text.ToObject<QiniuModel>();
            if (result.Code==200)
            {
                return QiniuAddress + "/" + model.key;
            }
            return null;
        }
        
        /// <summary>
        ///  删除七牛云里的图片
        /// </summary>
        /// <param name="filePath">这里是七牛云存的地址</param>
        /// <returns></returns>
        public async Task<int> Delete(string filePath) 
        {
            string[] sArray = filePath.Split(new string[] { QiniuAddress+"/" }, StringSplitOptions.RemoveEmptyEntries);
            BucketManager bucketManager = new BucketManager(new Mac(AccessKey, SecretKey), new Config());
            HttpResult result = await bucketManager.Delete(bucket, sArray[0]);
            return result.Code;
        }
       
        /// <summary>
        /// 通过本地地址上传七牛云,存本地
        /// </summary>
        /// <param name="url">图片本地地址</param>
        /// <returns></returns>
        public async Task<string> Upload(string url) 
        {
            string saveKey = System.IO.Path.GetFileName(url);
            Mac mac = new Mac(AccessKey, SecretKey);
            string localFile = url; 
            PutPolicy putPolicy = new PutPolicy();
            // 如果需要设置为"覆盖"上传(如果云端已有同名文件则覆盖),请使用 SCOPE = "BUCKET:KEY"
            // putPolicy.Scope = bucket + ":" + saveKey;
            putPolicy.Scope = bucket;
            // 上传策略有效期(对应于生成的凭证的有效期)          
            putPolicy.SetExpires(3600);
            // 上传到云端多少天后自动删除该文件,如果不设置(即保持默认默认)则不删除
            //putPolicy.DeleteAfterDays = 1;
            putPolicy.ReturnBody = "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"fsiz\":$(fsize),\"bucket\":\"$(bucket)\",\"name\":\"$(x:name)\"}";
            // 生成上传凭证                    
            string jstr = putPolicy.ToJsonString();
            string token = Auth.CreateUploadToken(mac, jstr);
            //Config配置类中可以配置区域,比如在我在七牛云上创建的fanin这个存储空间的区域选择的是“华南”这里就将它设为Zone=Zone.ZONE_CN_South 
            //UseHttps表示:是否采用https域名
            //UseCdnDomains表示:上传是否使用CDN上传加速
            //MaxRetryTimes表示:重试请求次数
            UploadManager um = new UploadManager(new Config() { Zone = Zone.ZoneCnSouth, UseHttps = true, UseCdnDomains = true, MaxRetryTimes = 3 });
            HttpResult result =await um.UploadFile(localFile, saveKey, token, new PutExtra());
            //UploadManager um = new UploadManager(new Config() { Zone = Zone.ZoneCnSouth, UseHttps = true, UseCdnDomains = true, MaxRetryTimes = 3 });
            //HttpResult result = await um.UploadFile(localFile, saveKey, token, new PutExtra());
            QiniuModel model = new QiniuModel();
            if (result.Code == 200)
            {
                model = result.Text.ToObject<QiniuModel>();
            }
            return QiniuAddress + "/" + model.key;
        }
        
        /// <summary>
        /// 上传apk安装包
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public async Task<string> UploadFile(HttpPostedFileBase file,string url)
        {
            var aa= Crc32.CheckSumStream(file.InputStream);
            string saveKey = "xdjmvc/" + System.IO.Path.GetFileName(url);
            //string saveKey = "xdjmvc/" + file.FileName; //这个myfile 相当于一个文件夹,是我们只设定的。2.png是我们上传文件的文件名,上传成功后通过它来读
            Mac mac = new Mac(AccessKey, SecretKey); // 生成(上传)凭证时需要使用此Mac
            PutPolicy putPolicy = new PutPolicy();
            // 如果需要设置为"覆盖"上传(如果云端已有同名文件则覆盖),请使用 SCOPE = "BUCKET:KEY"
            // putPolicy.Scope = bucket + ":" + saveKey;
            putPolicy.Scope = "xdjapk";
            // 上传策略有效期(对应于生成的凭证的有效期)          
            putPolicy.SetExpires(3600);
            
            // 上传到云端多少天后自动删除该文件,如果不设置(即保持默认默认)则不删除
            //putPolicy.DeleteAfterDays = 1;
            putPolicy.ReturnBody = "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"fsiz\":$(fsize),\"bucket\":\"$(bucket)\",\"name\":\"$(x:name)\"}";
            // 生成上传凭证                    
            string token = Auth.CreateUploadToken(mac, putPolicy.ToJsonString());//token生成
            //UploadManager um = new UploadManager(new Config() { Zone = Zone.ZoneCnSouth, UseHttps = true, UseCdnDomains = true, MaxRetryTimes = 3 });
            //HttpResult result = await um.UploadFile(url, saveKey, token, new PutExtra());
            FormUploader target = new FormUploader(new Config() { Zone = Zone.ZoneCnSouth, UseHttps = true, UseCdnDomains = true, MaxRetryTimes = 3 });
            HttpResult result = await target.UploadStream(file.InputStream, saveKey, token, new PutExtra());
            QiniuModel model = new QiniuModel();
            model = result.Text.ToObject<QiniuModel>();
            if (result.Code == 200)
            {
                return QiniuAppAddress + "/" + model.key;
            }
            return null;
        }
        #region 生成随机字符
        /// <summary>
        /// 生成随机字符
        /// </summary>
        /// <param name="length">字符长度</param>
        /// <param name="isSleep">是否要在生成前将当前线程阻止以避免重复</param>
        /// <param name="type">字符类型"num":数字类型;"str":纯字母;为空或者其他时,是数字和字母混合随机数</param>
        /// <returns>随机字符组成的字符串</returns>
        public static string Chars(int length, bool isSleep, string type)
        {
            if (isSleep) System.Threading.Thread.Sleep(3);

            char[] chars = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
            string result = "";
            //  给一个时间种子,防止重复
            Random random = new Random(~unchecked((int)DateTime.Now.Ticks));
            if (type == "num")
            {
                //  生成纯数字随机数
                for (int i = 0; i < length; i++)
                {
                    int rnd = random.Next(10);
                    result += chars[rnd];
                }
            }
            else if (type == "str")
            {
                //   纯字母随机数
                int rnd = random.Next(11, 36);
                result += chars[rnd];
            }
            else
            {
                //  数字字符混合随机数
                for (int i = 0; i < length; i++)
                {
                    int rnd = random.Next(36);
                    result += chars[rnd];
                }
            }
            return result;
        }
        #endregion
        

        /// <summary>
        /// 简单上传-上传字节数据
        /// </summary>
        public async Task<string> UploadData(string url)
        {
            // 生成(上传)凭证时需要使用此Mac
            // 这个示例单独使用了一个Settings类,其中包含AccessKey和SecretKey
            // 实际应用中,请自行设置您的AccessKey和SecretKey
            Mac mac = new Mac(AccessKey, SecretKey); // 生成(上传)凭证时需要使用此Mac
            string bucket = "xdjapk";
            string saveKey = "xdjmvc/"+ Chars(6,true,"") + ".apk";
            byte[] data = System.IO.File.ReadAllBytes(url);
            //byte[] data = System.Text.Encoding.UTF8.GetBytes("Hello World!");
            // 上传策略,参见 
            // https://developer.qiniu.com/kodo/manual/put-policy
            PutPolicy putPolicy = new PutPolicy();
            // 如果需要设置为"覆盖"上传(如果云端已有同名文件则覆盖),请使用 SCOPE = "BUCKET:KEY"
            // putPolicy.Scope = bucket + ":" + saveKey;
            putPolicy.Scope = bucket;
            // 上传策略有效期(对应于生成的凭证的有效期)          
            putPolicy.SetExpires(3600);
            // 上传到云端多少天后自动删除该文件,如果不设置(即保持默认默认)则不删除
            putPolicy.DeleteAfterDays = 1;
            // 生成上传凭证,参见
            // https://developer.qiniu.com/kodo/manual/upload-token            
            string jstr = putPolicy.ToJsonString();
            string token = Auth.CreateUploadToken(mac, jstr);
            FormUploader fu = new FormUploader(new Config() { Zone = Zone.ZoneCnSouth, UseHttps = true, UseCdnDomains = true, MaxRetryTimes = 3 });
            Qiniu.Http.HttpResult result =await fu.UploadData(data, saveKey, token, new PutExtra());
            QiniuModel model = new QiniuModel();
            model = result.Text.ToObject<QiniuModel>();
            if (result.Code == 200)
            {
                return QiniuAppAddress + "/" + model.key;
            }
            return null;
        }

        /// <summary>
        /// 上传apk安装包
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public async Task<string> UploadFile(HttpPostedFileBase file)
        {
            string name = Chars(6, true, "");
            var newFileName = name + ".apk";
            string saveKey = "xdjmvc/" + newFileName;
            //string saveKey = "xdjmvc/" + file.FileName; //这个myfile 相当于一个文件夹,是我们只设定的。2.png是我们上传文件的文件名,上传成功后通过它来读
            Mac mac = new Mac(AccessKey, SecretKey); // 生成(上传)凭证时需要使用此Mac
            PutPolicy putPolicy = new PutPolicy();
            // 如果需要设置为"覆盖"上传(如果云端已有同名文件则覆盖),请使用 SCOPE = "BUCKET:KEY"
            // putPolicy.Scope = bucket + ":" + saveKey;
            putPolicy.Scope = "xdjapk";
            // 上传策略有效期(对应于生成的凭证的有效期)          
            putPolicy.SetExpires(3600);
            // 上传到云端多少天后自动删除该文件,如果不设置(即保持默认默认)则不删除
            //putPolicy.DeleteAfterDays = 1;
            putPolicy.ReturnBody = "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"fsiz\":$(fsize),\"bucket\":\"$(bucket)\",\"name\":\"$(x:name)\"}";
            // 生成上传凭证                    
            string token = Auth.CreateUploadToken(mac, putPolicy.ToJsonString());//token生成
            FormUploader target = new FormUploader(new Config() { Zone = Zone.ZoneCnSouth, UseHttps = true, UseCdnDomains = true, MaxRetryTimes = 3 });
            BucketManager bucketManager = new BucketManager(mac, new Config() { Zone = Zone.ZoneCnSouth, UseHttps = true, UseCdnDomains = true, MaxRetryTimes = 3 });
            await bucketManager.Delete(bucket, saveKey);
            HttpResult result = await target.UploadStream(file.InputStream, saveKey, token, new PutExtra());
            QiniuModel model = new QiniuModel();
            model = result.Text.ToObject<QiniuModel>();
            if (result.Code == 200)
            {
                return QiniuAppAddress + "/" + model.key;
            }
            return null;
        }
    }
}

这次这个经历真的好好教育了我,作为年轻人一定得多学习。

对了在补充点小知识,关于前端上传文件到服务器,文件过大解决方法

在webconfig文件里去配置一下代码

 <system.web>
      
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.6.1" appRequestQueueLimit="100" executionTimeout="80" maxRequestLength="2147483647" useFullyQualifiedRedirectUrl="false" />
  </system.web>
    

<system.webServer>
        <security>
            <requestFiltering>
                <requestLimits maxAllowedContentLength="2147483647" />
            </requestFiltering>
        </security>
    </system.webServer>

多了这里我这个类库也是从CSDN上下的,不过都要收费,我这里免费提供给大家,希望大家不喜勿喷,喜欢的点点小赞,支持一下博主,谢谢大家

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值