feat : first
This commit is contained in:
64
DeleteEmptyFolders.java
Normal file
64
DeleteEmptyFolders.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class DeleteEmptyFolders {
|
||||||
|
|
||||||
|
// 白名单路径集合
|
||||||
|
private static final Set<String> WHITELIST_PATHS = new HashSet<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
// 添加白名单路径,请根据实际需求修改
|
||||||
|
// WHITELIST_PATHS.add("/Users/zhanglaiman/WorkSpace/Molistar/core/src/main/java/com");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
String targetDir = "/Users/zhanglaiman/WorkSpace/Molistar/app";
|
||||||
|
File rootDir = new File(targetDir);
|
||||||
|
deleteEmptyFolders(rootDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isDirectoryEmpty(File dir) {
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
if (files == null || files.length == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
if (!isDirectoryEmpty(file)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (file.getName().endsWith(".java")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void deleteEmptyFolders(File dir) {
|
||||||
|
if (dir == null || !dir.exists() || dir.isFile()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跳过白名单中的路径
|
||||||
|
if (WHITELIST_PATHS.contains(dir.getAbsolutePath())) {
|
||||||
|
System.out.println("跳过白名单路径: " + dir.getAbsolutePath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
deleteEmptyFolders(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDirectoryEmpty(dir)) {
|
||||||
|
System.out.println("删除空文件夹: " + dir.getAbsolutePath());
|
||||||
|
dir.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
998
apkinfo.py
Normal file
998
apkinfo.py
Normal file
@@ -0,0 +1,998 @@
|
|||||||
|
# This file is part of Androguard.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2012, Anthony Desnos <desnos at t0t0.fr>
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS-IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import StringIO
|
||||||
|
from struct import pack, unpack
|
||||||
|
from xml.sax.saxutils import escape
|
||||||
|
from zlib import crc32
|
||||||
|
import re
|
||||||
|
import collections
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import types
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
import imp
|
||||||
|
|
||||||
|
from xml.dom import minidom
|
||||||
|
|
||||||
|
NS_ANDROID_URI = 'http://schemas.android.com/apk/res/android'
|
||||||
|
|
||||||
|
ZIPMODULE = 1
|
||||||
|
|
||||||
|
|
||||||
|
def read(filename, binary=True):
|
||||||
|
with open(filename, 'rb' if binary else 'r') as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
def sign_apk(filename, keystore, storepass):
|
||||||
|
from subprocess import Popen, PIPE, STDOUT
|
||||||
|
compile = Popen([CONF["PATH_JARSIGNER"], "-sigalg", "MD5withRSA",
|
||||||
|
"-digestalg", "SHA1", "-storepass", storepass, "-keystore",
|
||||||
|
keystore, filename, "alias_name"],
|
||||||
|
stdout=PIPE,
|
||||||
|
stderr=STDOUT)
|
||||||
|
stdout, stderr = compile.communicate()
|
||||||
|
|
||||||
|
|
||||||
|
class Error(Exception):
|
||||||
|
"""Base class for exceptions in this module."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FileNotPresent(Error):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
######################################################## APK FORMAT ########################################################
|
||||||
|
class APK(object):
|
||||||
|
"""
|
||||||
|
This class can access to all elements in an APK file
|
||||||
|
|
||||||
|
:param filename: specify the path of the file, or raw data
|
||||||
|
:param raw: specify if the filename is a path or raw data (optional)
|
||||||
|
:param mode: specify the mode to open the file (optional)
|
||||||
|
:param magic_file: specify the magic file (optional)
|
||||||
|
:param zipmodule: specify the type of zip module to use (0:chilkat, 1:zipfile, 2:patch zipfile)
|
||||||
|
|
||||||
|
:type filename: string
|
||||||
|
:type raw: boolean
|
||||||
|
:type mode: string
|
||||||
|
:type magic_file: string
|
||||||
|
:type zipmodule: int
|
||||||
|
|
||||||
|
:Example:
|
||||||
|
APK("myfile.apk")
|
||||||
|
APK(read("myfile.apk"), raw=True)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
filename,
|
||||||
|
raw=False,
|
||||||
|
mode="r",
|
||||||
|
magic_file=None,
|
||||||
|
zipmodule=ZIPMODULE):
|
||||||
|
self.filename = filename
|
||||||
|
|
||||||
|
self.xml = {}
|
||||||
|
self.axml = {}
|
||||||
|
self.arsc = {}
|
||||||
|
|
||||||
|
self.package = ""
|
||||||
|
self.androidversion = {}
|
||||||
|
self.permissions = []
|
||||||
|
self.declared_permissions = {}
|
||||||
|
self.valid_apk = False
|
||||||
|
|
||||||
|
self.files = {}
|
||||||
|
self.files_crc32 = {}
|
||||||
|
|
||||||
|
self.magic_file = magic_file
|
||||||
|
|
||||||
|
if raw is True:
|
||||||
|
self.__raw = filename
|
||||||
|
else:
|
||||||
|
self.__raw = read(filename)
|
||||||
|
|
||||||
|
self.zipmodule = zipmodule
|
||||||
|
|
||||||
|
if zipmodule == 0:
|
||||||
|
self.zip = ChilkatZip(self.__raw)
|
||||||
|
elif zipmodule == 2:
|
||||||
|
from androguard.patch import zipfile
|
||||||
|
self.zip = zipfile.ZipFile(StringIO.StringIO(self.__raw), mode=mode)
|
||||||
|
else:
|
||||||
|
import zipfile
|
||||||
|
self.zip = zipfile.ZipFile(StringIO.StringIO(self.__raw), mode=mode)
|
||||||
|
|
||||||
|
for i in self.zip.namelist():
|
||||||
|
if i == "AndroidManifest.xml":
|
||||||
|
self.axml[i] = AXMLPrinter(self.zip.read(i))
|
||||||
|
try:
|
||||||
|
self.xml[i] = minidom.parseString(self.axml[i].get_buff())
|
||||||
|
except:
|
||||||
|
self.xml[i] = None
|
||||||
|
|
||||||
|
if self.xml[i] != None:
|
||||||
|
self.package = self.xml[i].documentElement.getAttribute(
|
||||||
|
"package")
|
||||||
|
self.androidversion[
|
||||||
|
"Code"
|
||||||
|
] = self.xml[i].documentElement.getAttributeNS(
|
||||||
|
NS_ANDROID_URI, "versionCode")
|
||||||
|
self.androidversion[
|
||||||
|
"Name"
|
||||||
|
] = self.xml[i].documentElement.getAttributeNS(
|
||||||
|
NS_ANDROID_URI, "versionName")
|
||||||
|
|
||||||
|
self.valid_apk = True
|
||||||
|
|
||||||
|
def get_AndroidManifest(self):
|
||||||
|
"""
|
||||||
|
Return the Android Manifest XML file
|
||||||
|
|
||||||
|
:rtype: xml object
|
||||||
|
"""
|
||||||
|
return self.xml["AndroidManifest.xml"]
|
||||||
|
|
||||||
|
def is_valid_APK(self):
|
||||||
|
"""
|
||||||
|
Return true if the APK is valid, false otherwise
|
||||||
|
|
||||||
|
:rtype: boolean
|
||||||
|
"""
|
||||||
|
return self.valid_apk
|
||||||
|
|
||||||
|
def get_filename(self):
|
||||||
|
"""
|
||||||
|
Return the filename of the APK
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
|
return self.filename
|
||||||
|
|
||||||
|
def get_package(self):
|
||||||
|
"""
|
||||||
|
Return the name of the package
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
|
return self.package
|
||||||
|
|
||||||
|
def get_version_code(self):
|
||||||
|
"""
|
||||||
|
Return the android version code
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
|
return self.androidversion["Code"]
|
||||||
|
|
||||||
|
def get_version_name(self):
|
||||||
|
"""
|
||||||
|
Return the android version name
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
|
return self.androidversion["Name"]
|
||||||
|
|
||||||
|
def get_raw(self):
|
||||||
|
"""
|
||||||
|
Return raw bytes of the APK
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
|
return self.__raw
|
||||||
|
|
||||||
|
def get_elements(self, tag_name, attribute):
|
||||||
|
"""
|
||||||
|
Return elements in xml files which match with the tag name and the specific attribute
|
||||||
|
|
||||||
|
:param tag_name: a string which specify the tag name
|
||||||
|
:param attribute: a string which specify the attribute
|
||||||
|
"""
|
||||||
|
l = []
|
||||||
|
for i in self.xml:
|
||||||
|
for item in self.xml[i].getElementsByTagName(tag_name):
|
||||||
|
value = item.getAttributeNS(NS_ANDROID_URI, attribute)
|
||||||
|
value = self.format_value(value)
|
||||||
|
|
||||||
|
l.append(str(value))
|
||||||
|
return l
|
||||||
|
|
||||||
|
def format_value(self, value):
|
||||||
|
if len(value) > 0:
|
||||||
|
if value[0] == ".":
|
||||||
|
value = self.package + value
|
||||||
|
else:
|
||||||
|
v_dot = value.find(".")
|
||||||
|
if v_dot == 0:
|
||||||
|
value = self.package + "." + value
|
||||||
|
elif v_dot == -1:
|
||||||
|
value = self.package + "." + value
|
||||||
|
return value
|
||||||
|
|
||||||
|
def get_element(self, tag_name, attribute, **attribute_filter):
|
||||||
|
"""
|
||||||
|
Return element in xml files which match with the tag name and the specific attribute
|
||||||
|
|
||||||
|
:param tag_name: specify the tag name
|
||||||
|
:type tag_name: string
|
||||||
|
:param attribute: specify the attribute
|
||||||
|
:type attribute: string
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
|
for i in self.xml:
|
||||||
|
for item in self.xml[i].getElementsByTagName(tag_name):
|
||||||
|
skip_this_item = False
|
||||||
|
for attr, val in attribute_filter.items():
|
||||||
|
attr_val = item.getAttributeNS(NS_ANDROID_URI, attr)
|
||||||
|
if attr_val != val:
|
||||||
|
skip_this_item = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if skip_this_item:
|
||||||
|
continue
|
||||||
|
|
||||||
|
value = item.getAttributeNS(NS_ANDROID_URI, attribute)
|
||||||
|
|
||||||
|
if len(value) > 0:
|
||||||
|
return value
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_max_sdk_version(self):
|
||||||
|
"""
|
||||||
|
Return the android:maxSdkVersion attribute
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
|
return self.get_element("uses-sdk", "maxSdkVersion")
|
||||||
|
|
||||||
|
def get_min_sdk_version(self):
|
||||||
|
"""
|
||||||
|
Return the android:minSdkVersion attribute
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
|
return self.get_element("uses-sdk", "minSdkVersion")
|
||||||
|
|
||||||
|
def get_target_sdk_version(self):
|
||||||
|
"""
|
||||||
|
Return the android:targetSdkVersion attribute
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
|
return self.get_element("uses-sdk", "targetSdkVersion")
|
||||||
|
|
||||||
|
def get_android_manifest_axml(self):
|
||||||
|
"""
|
||||||
|
Return the :class:`AXMLPrinter` object which corresponds to the AndroidManifest.xml file
|
||||||
|
|
||||||
|
:rtype: :class:`AXMLPrinter`
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self.axml["AndroidManifest.xml"]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_android_manifest_xml(self):
|
||||||
|
"""
|
||||||
|
Return the xml object which corresponds to the AndroidManifest.xml file
|
||||||
|
|
||||||
|
:rtype: object
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self.xml["AndroidManifest.xml"]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
|
||||||
|
print "PACKAGE: ", self.get_package()
|
||||||
|
print "VERSION NAME:", self.get_version_name()
|
||||||
|
print "VERSION CODE:", self.get_version_code()
|
||||||
|
|
||||||
|
################################## AXML FORMAT ########################################
|
||||||
|
# Translated from
|
||||||
|
# http://code.google.com/p/android4me/source/browse/src/android/content/res/AXmlResourceParser.java
|
||||||
|
|
||||||
|
UTF8_FLAG = 0x00000100
|
||||||
|
CHUNK_STRINGPOOL_TYPE = 0x001C0001
|
||||||
|
CHUNK_NULL_TYPE = 0x00000000
|
||||||
|
|
||||||
|
|
||||||
|
class StringBlock(object):
|
||||||
|
|
||||||
|
def __init__(self, buff):
|
||||||
|
self.start = buff.get_idx()
|
||||||
|
self._cache = {}
|
||||||
|
self.header_size, self.header = self.skipNullPadding(buff)
|
||||||
|
|
||||||
|
self.chunkSize = unpack('<i', buff.read(4))[0]
|
||||||
|
self.stringCount = unpack('<i', buff.read(4))[0]
|
||||||
|
self.styleOffsetCount = unpack('<i', buff.read(4))[0]
|
||||||
|
|
||||||
|
self.flags = unpack('<i', buff.read(4))[0]
|
||||||
|
self.m_isUTF8 = ((self.flags & UTF8_FLAG) != 0)
|
||||||
|
|
||||||
|
self.stringsOffset = unpack('<i', buff.read(4))[0]
|
||||||
|
self.stylesOffset = unpack('<i', buff.read(4))[0]
|
||||||
|
|
||||||
|
self.m_stringOffsets = []
|
||||||
|
self.m_styleOffsets = []
|
||||||
|
self.m_charbuff = ""
|
||||||
|
self.m_styles = []
|
||||||
|
|
||||||
|
for i in range(0, self.stringCount):
|
||||||
|
self.m_stringOffsets.append(unpack('<i', buff.read(4))[0])
|
||||||
|
|
||||||
|
for i in range(0, self.styleOffsetCount):
|
||||||
|
self.m_styleOffsets.append(unpack('<i', buff.read(4))[0])
|
||||||
|
|
||||||
|
size = self.chunkSize - self.stringsOffset
|
||||||
|
if self.stylesOffset != 0:
|
||||||
|
size = self.stylesOffset - self.stringsOffset
|
||||||
|
|
||||||
|
# FIXME
|
||||||
|
if (size % 4) != 0:
|
||||||
|
warning("ooo")
|
||||||
|
|
||||||
|
self.m_charbuff = buff.read(size)
|
||||||
|
|
||||||
|
if self.stylesOffset != 0:
|
||||||
|
size = self.chunkSize - self.stylesOffset
|
||||||
|
|
||||||
|
# FIXME
|
||||||
|
if (size % 4) != 0:
|
||||||
|
warning("ooo")
|
||||||
|
|
||||||
|
for i in range(0, size / 4):
|
||||||
|
self.m_styles.append(unpack('<i', buff.read(4))[0])
|
||||||
|
|
||||||
|
def skipNullPadding(self, buff):
|
||||||
|
|
||||||
|
def readNext(buff, first_run=True):
|
||||||
|
header = unpack('<i', buff.read(4))[0]
|
||||||
|
|
||||||
|
if header == CHUNK_NULL_TYPE and first_run:
|
||||||
|
info("Skipping null padding in StringBlock header")
|
||||||
|
header = readNext(buff, first_run=False)
|
||||||
|
elif header != CHUNK_STRINGPOOL_TYPE:
|
||||||
|
warning("Invalid StringBlock header")
|
||||||
|
|
||||||
|
return header
|
||||||
|
|
||||||
|
header = readNext(buff)
|
||||||
|
return header >> 8, header & 0xFF
|
||||||
|
|
||||||
|
def getString(self, idx):
|
||||||
|
if idx in self._cache:
|
||||||
|
return self._cache[idx]
|
||||||
|
|
||||||
|
if idx < 0 or not self.m_stringOffsets or idx >= len(
|
||||||
|
self.m_stringOffsets):
|
||||||
|
return ""
|
||||||
|
|
||||||
|
offset = self.m_stringOffsets[idx]
|
||||||
|
|
||||||
|
if self.m_isUTF8:
|
||||||
|
self._cache[idx] = self.decode8(offset)
|
||||||
|
else:
|
||||||
|
self._cache[idx] = self.decode16(offset)
|
||||||
|
|
||||||
|
return self._cache[idx]
|
||||||
|
|
||||||
|
def getStyle(self, idx):
|
||||||
|
# FIXME
|
||||||
|
return self.m_styles[idx]
|
||||||
|
|
||||||
|
def decode8(self, offset):
|
||||||
|
str_len, skip = self.decodeLength(offset, 1)
|
||||||
|
offset += skip
|
||||||
|
|
||||||
|
encoded_bytes, skip = self.decodeLength(offset, 1)
|
||||||
|
offset += skip
|
||||||
|
|
||||||
|
data = self.m_charbuff[offset: offset + encoded_bytes]
|
||||||
|
|
||||||
|
return self.decode_bytes(data, 'utf-8', str_len)
|
||||||
|
|
||||||
|
def decode16(self, offset):
|
||||||
|
str_len, skip = self.decodeLength(offset, 2)
|
||||||
|
offset += skip
|
||||||
|
|
||||||
|
encoded_bytes = str_len * 2
|
||||||
|
|
||||||
|
data = self.m_charbuff[offset: offset + encoded_bytes]
|
||||||
|
|
||||||
|
return self.decode_bytes(data, 'utf-16', str_len)
|
||||||
|
|
||||||
|
def decode_bytes(self, data, encoding, str_len):
|
||||||
|
string = data.decode(encoding, 'replace')
|
||||||
|
if len(string) != str_len:
|
||||||
|
warning("invalid decoded string length")
|
||||||
|
return string
|
||||||
|
|
||||||
|
def decodeLength(self, offset, sizeof_char):
|
||||||
|
length = ord(self.m_charbuff[offset])
|
||||||
|
|
||||||
|
sizeof_2chars = sizeof_char << 1
|
||||||
|
fmt_chr = 'B' if sizeof_char == 1 else 'H'
|
||||||
|
fmt = "<2" + fmt_chr
|
||||||
|
|
||||||
|
length1, length2 = unpack(fmt, self.m_charbuff[offset:(offset + sizeof_2chars)])
|
||||||
|
|
||||||
|
highbit = 0x80 << (8 * (sizeof_char - 1))
|
||||||
|
|
||||||
|
if (length & highbit) != 0:
|
||||||
|
return ((length1 & ~highbit) << (8 * sizeof_char)) | length2, sizeof_2chars
|
||||||
|
else:
|
||||||
|
return length1, sizeof_char
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
print "StringBlock(%x, %x, %x, %x, %x, %x" % (
|
||||||
|
self.start,
|
||||||
|
self.header,
|
||||||
|
self.header_size,
|
||||||
|
self.chunkSize,
|
||||||
|
self.stringsOffset,
|
||||||
|
self.flags)
|
||||||
|
for i in range(0, len(self.m_stringOffsets)):
|
||||||
|
print i, repr(self.getString(i))
|
||||||
|
|
||||||
|
START_DOCUMENT = 0
|
||||||
|
END_DOCUMENT = 1
|
||||||
|
START_TAG = 2
|
||||||
|
END_TAG = 3
|
||||||
|
TEXT = 4
|
||||||
|
|
||||||
|
ATTRIBUTE_IX_NAMESPACE_URI = 0
|
||||||
|
ATTRIBUTE_IX_NAME = 1
|
||||||
|
ATTRIBUTE_IX_VALUE_STRING = 2
|
||||||
|
ATTRIBUTE_IX_VALUE_TYPE = 3
|
||||||
|
ATTRIBUTE_IX_VALUE_DATA = 4
|
||||||
|
ATTRIBUTE_LENGHT = 5
|
||||||
|
|
||||||
|
CHUNK_AXML_FILE = 0x00080003
|
||||||
|
CHUNK_RESOURCEIDS = 0x00080180
|
||||||
|
CHUNK_XML_FIRST = 0x00100100
|
||||||
|
CHUNK_XML_START_NAMESPACE = 0x00100100
|
||||||
|
CHUNK_XML_END_NAMESPACE = 0x00100101
|
||||||
|
CHUNK_XML_START_TAG = 0x00100102
|
||||||
|
CHUNK_XML_END_TAG = 0x00100103
|
||||||
|
CHUNK_XML_TEXT = 0x00100104
|
||||||
|
CHUNK_XML_LAST = 0x00100104
|
||||||
|
|
||||||
|
|
||||||
|
class AXMLParser(object):
|
||||||
|
|
||||||
|
def __init__(self, raw_buff):
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
self.valid_axml = True
|
||||||
|
self.buff = BuffHandle(raw_buff)
|
||||||
|
|
||||||
|
axml_file = unpack('<L', self.buff.read(4))[0]
|
||||||
|
|
||||||
|
if axml_file == CHUNK_AXML_FILE:
|
||||||
|
self.buff.read(4)
|
||||||
|
|
||||||
|
self.sb = StringBlock(self.buff)
|
||||||
|
|
||||||
|
self.m_resourceIDs = []
|
||||||
|
self.m_prefixuri = {}
|
||||||
|
self.m_uriprefix = {}
|
||||||
|
self.m_prefixuriL = []
|
||||||
|
|
||||||
|
self.visited_ns = []
|
||||||
|
else:
|
||||||
|
self.valid_axml = False
|
||||||
|
warning("Not a valid xml file")
|
||||||
|
|
||||||
|
def is_valid(self):
|
||||||
|
return self.valid_axml
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.m_event = -1
|
||||||
|
self.m_lineNumber = -1
|
||||||
|
self.m_name = -1
|
||||||
|
self.m_namespaceUri = -1
|
||||||
|
self.m_attributes = []
|
||||||
|
self.m_idAttribute = -1
|
||||||
|
self.m_classAttribute = -1
|
||||||
|
self.m_styleAttribute = -1
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
self.doNext()
|
||||||
|
return self.m_event
|
||||||
|
|
||||||
|
def doNext(self):
|
||||||
|
if self.m_event == END_DOCUMENT:
|
||||||
|
return
|
||||||
|
|
||||||
|
event = self.m_event
|
||||||
|
|
||||||
|
self.reset()
|
||||||
|
while True:
|
||||||
|
chunkType = -1
|
||||||
|
|
||||||
|
# Fake END_DOCUMENT event.
|
||||||
|
if event == END_TAG:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# START_DOCUMENT
|
||||||
|
if event == START_DOCUMENT:
|
||||||
|
chunkType = CHUNK_XML_START_TAG
|
||||||
|
else:
|
||||||
|
if self.buff.end():
|
||||||
|
self.m_event = END_DOCUMENT
|
||||||
|
break
|
||||||
|
chunkType = unpack('<L', self.buff.read(4))[0]
|
||||||
|
|
||||||
|
if chunkType == CHUNK_RESOURCEIDS:
|
||||||
|
chunkSize = unpack('<L', self.buff.read(4))[0]
|
||||||
|
# FIXME
|
||||||
|
if chunkSize < 8 or chunkSize % 4 != 0:
|
||||||
|
warning("Invalid chunk size")
|
||||||
|
|
||||||
|
for i in range(0, chunkSize / 4 - 2):
|
||||||
|
self.m_resourceIDs.append(
|
||||||
|
unpack('<L', self.buff.read(4))[0])
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
# FIXME
|
||||||
|
if chunkType < CHUNK_XML_FIRST or chunkType > CHUNK_XML_LAST:
|
||||||
|
warning("invalid chunk type")
|
||||||
|
|
||||||
|
# Fake START_DOCUMENT event.
|
||||||
|
if chunkType == CHUNK_XML_START_TAG and event == -1:
|
||||||
|
self.m_event = START_DOCUMENT
|
||||||
|
break
|
||||||
|
|
||||||
|
self.buff.read(4) # /*chunkSize*/
|
||||||
|
lineNumber = unpack('<L', self.buff.read(4))[0]
|
||||||
|
self.buff.read(4) # 0xFFFFFFFF
|
||||||
|
|
||||||
|
if chunkType == CHUNK_XML_START_NAMESPACE or chunkType == CHUNK_XML_END_NAMESPACE:
|
||||||
|
if chunkType == CHUNK_XML_START_NAMESPACE:
|
||||||
|
prefix = unpack('<L', self.buff.read(4))[0]
|
||||||
|
uri = unpack('<L', self.buff.read(4))[0]
|
||||||
|
|
||||||
|
self.m_prefixuri[prefix] = uri
|
||||||
|
self.m_uriprefix[uri] = prefix
|
||||||
|
self.m_prefixuriL.append((prefix, uri))
|
||||||
|
self.ns = uri
|
||||||
|
else:
|
||||||
|
self.ns = -1
|
||||||
|
self.buff.read(4)
|
||||||
|
self.buff.read(4)
|
||||||
|
(prefix, uri) = self.m_prefixuriL.pop()
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.m_lineNumber = lineNumber
|
||||||
|
|
||||||
|
if chunkType == CHUNK_XML_START_TAG:
|
||||||
|
self.m_namespaceUri = unpack('<L', self.buff.read(4))[0]
|
||||||
|
self.m_name = unpack('<L', self.buff.read(4))[0]
|
||||||
|
|
||||||
|
# FIXME
|
||||||
|
self.buff.read(4) # flags
|
||||||
|
|
||||||
|
attributeCount = unpack('<L', self.buff.read(4))[0]
|
||||||
|
self.m_idAttribute = (attributeCount >> 16) - 1
|
||||||
|
attributeCount = attributeCount & 0xFFFF
|
||||||
|
self.m_classAttribute = unpack('<L', self.buff.read(4))[0]
|
||||||
|
self.m_styleAttribute = (self.m_classAttribute >> 16) - 1
|
||||||
|
|
||||||
|
self.m_classAttribute = (self.m_classAttribute & 0xFFFF) - 1
|
||||||
|
|
||||||
|
for i in range(0, attributeCount * ATTRIBUTE_LENGHT):
|
||||||
|
self.m_attributes.append(unpack('<L', self.buff.read(4))[0])
|
||||||
|
|
||||||
|
for i in range(ATTRIBUTE_IX_VALUE_TYPE, len(self.m_attributes),
|
||||||
|
ATTRIBUTE_LENGHT):
|
||||||
|
self.m_attributes[i] = self.m_attributes[i] >> 24
|
||||||
|
|
||||||
|
self.m_event = START_TAG
|
||||||
|
break
|
||||||
|
|
||||||
|
if chunkType == CHUNK_XML_END_TAG:
|
||||||
|
self.m_namespaceUri = unpack('<L', self.buff.read(4))[0]
|
||||||
|
self.m_name = unpack('<L', self.buff.read(4))[0]
|
||||||
|
self.m_event = END_TAG
|
||||||
|
break
|
||||||
|
|
||||||
|
if chunkType == CHUNK_XML_TEXT:
|
||||||
|
self.m_name = unpack('<L', self.buff.read(4))[0]
|
||||||
|
|
||||||
|
# FIXME
|
||||||
|
self.buff.read(4)
|
||||||
|
self.buff.read(4)
|
||||||
|
|
||||||
|
self.m_event = TEXT
|
||||||
|
break
|
||||||
|
|
||||||
|
def getPrefixByUri(self, uri):
|
||||||
|
try:
|
||||||
|
return self.m_uriprefix[uri]
|
||||||
|
except KeyError:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
def getPrefix(self):
|
||||||
|
try:
|
||||||
|
return self.sb.getString(self.m_uriprefix[self.m_namespaceUri])
|
||||||
|
except KeyError:
|
||||||
|
return u''
|
||||||
|
|
||||||
|
def getName(self):
|
||||||
|
if self.m_name == -1 or (self.m_event != START_TAG and
|
||||||
|
self.m_event != END_TAG):
|
||||||
|
return u''
|
||||||
|
|
||||||
|
return self.sb.getString(self.m_name)
|
||||||
|
|
||||||
|
def getText(self):
|
||||||
|
if self.m_name == -1 or self.m_event != TEXT:
|
||||||
|
return u''
|
||||||
|
|
||||||
|
return self.sb.getString(self.m_name)
|
||||||
|
|
||||||
|
def getNamespacePrefix(self, pos):
|
||||||
|
prefix = self.m_prefixuriL[pos][0]
|
||||||
|
return self.sb.getString(prefix)
|
||||||
|
|
||||||
|
def getNamespaceUri(self, pos):
|
||||||
|
uri = self.m_prefixuriL[pos][1]
|
||||||
|
return self.sb.getString(uri)
|
||||||
|
|
||||||
|
def getXMLNS(self):
|
||||||
|
buff = ""
|
||||||
|
for i in self.m_uriprefix:
|
||||||
|
if i not in self.visited_ns:
|
||||||
|
buff += "xmlns:%s=\"%s\"\n" % (
|
||||||
|
self.sb.getString(self.m_uriprefix[i]),
|
||||||
|
self.sb.getString(self.m_prefixuri[self.m_uriprefix[i]]))
|
||||||
|
self.visited_ns.append(i)
|
||||||
|
return buff
|
||||||
|
|
||||||
|
def getNamespaceCount(self, pos):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def getAttributeOffset(self, index):
|
||||||
|
# FIXME
|
||||||
|
if self.m_event != START_TAG:
|
||||||
|
warning("Current event is not START_TAG.")
|
||||||
|
|
||||||
|
offset = index * 5
|
||||||
|
# FIXME
|
||||||
|
if offset >= len(self.m_attributes):
|
||||||
|
warning("Invalid attribute index")
|
||||||
|
|
||||||
|
return offset
|
||||||
|
|
||||||
|
def getAttributeCount(self):
|
||||||
|
if self.m_event != START_TAG:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
return len(self.m_attributes) / ATTRIBUTE_LENGHT
|
||||||
|
|
||||||
|
def getAttributePrefix(self, index):
|
||||||
|
offset = self.getAttributeOffset(index)
|
||||||
|
uri = self.m_attributes[offset + ATTRIBUTE_IX_NAMESPACE_URI]
|
||||||
|
|
||||||
|
prefix = self.getPrefixByUri(uri)
|
||||||
|
|
||||||
|
if prefix == -1:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return self.sb.getString(prefix)
|
||||||
|
|
||||||
|
def getAttributeName(self, index):
|
||||||
|
offset = self.getAttributeOffset(index)
|
||||||
|
name = self.m_attributes[offset + ATTRIBUTE_IX_NAME]
|
||||||
|
|
||||||
|
if name == -1:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
res = self.sb.getString(name)
|
||||||
|
if not res:
|
||||||
|
attr = self.m_resourceIDs[name]
|
||||||
|
if attr in SYSTEM_RESOURCES['attributes']['inverse']:
|
||||||
|
res = 'android:' + SYSTEM_RESOURCES['attributes']['inverse'][
|
||||||
|
attr
|
||||||
|
]
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
def getAttributeValueType(self, index):
|
||||||
|
offset = self.getAttributeOffset(index)
|
||||||
|
return self.m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE]
|
||||||
|
|
||||||
|
def getAttributeValueData(self, index):
|
||||||
|
offset = self.getAttributeOffset(index)
|
||||||
|
return self.m_attributes[offset + ATTRIBUTE_IX_VALUE_DATA]
|
||||||
|
|
||||||
|
def getAttributeValue(self, index):
|
||||||
|
offset = self.getAttributeOffset(index)
|
||||||
|
valueType = self.m_attributes[offset + ATTRIBUTE_IX_VALUE_TYPE]
|
||||||
|
if valueType == TYPE_STRING:
|
||||||
|
valueString = self.m_attributes[offset + ATTRIBUTE_IX_VALUE_STRING]
|
||||||
|
return self.sb.getString(valueString)
|
||||||
|
# WIP
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# resource constants
|
||||||
|
|
||||||
|
TYPE_ATTRIBUTE = 2
|
||||||
|
TYPE_DIMENSION = 5
|
||||||
|
TYPE_FIRST_COLOR_INT = 28
|
||||||
|
TYPE_FIRST_INT = 16
|
||||||
|
TYPE_FLOAT = 4
|
||||||
|
TYPE_FRACTION = 6
|
||||||
|
TYPE_INT_BOOLEAN = 18
|
||||||
|
TYPE_INT_DEC = 16
|
||||||
|
TYPE_INT_HEX = 17
|
||||||
|
TYPE_LAST_COLOR_INT = 31
|
||||||
|
TYPE_LAST_INT = 31
|
||||||
|
TYPE_NULL = 0
|
||||||
|
TYPE_REFERENCE = 1
|
||||||
|
TYPE_STRING = 3
|
||||||
|
|
||||||
|
TYPE_TABLE = {
|
||||||
|
TYPE_ATTRIBUTE: "attribute",
|
||||||
|
TYPE_DIMENSION: "dimension",
|
||||||
|
TYPE_FLOAT: "float",
|
||||||
|
TYPE_FRACTION: "fraction",
|
||||||
|
TYPE_INT_BOOLEAN: "int_boolean",
|
||||||
|
TYPE_INT_DEC: "int_dec",
|
||||||
|
TYPE_INT_HEX: "int_hex",
|
||||||
|
TYPE_NULL: "null",
|
||||||
|
TYPE_REFERENCE: "reference",
|
||||||
|
TYPE_STRING: "string",
|
||||||
|
}
|
||||||
|
|
||||||
|
RADIX_MULTS = [0.00390625, 3.051758E-005, 1.192093E-007, 4.656613E-010]
|
||||||
|
DIMENSION_UNITS = ["px", "dip", "sp", "pt", "in", "mm"]
|
||||||
|
FRACTION_UNITS = ["%", "%p"]
|
||||||
|
|
||||||
|
COMPLEX_UNIT_MASK = 15
|
||||||
|
|
||||||
|
|
||||||
|
def complexToFloat(xcomplex):
|
||||||
|
return (float)(xcomplex & 0xFFFFFF00) * RADIX_MULTS[(xcomplex >> 4) & 3]
|
||||||
|
|
||||||
|
|
||||||
|
def getPackage(id):
|
||||||
|
if id >> 24 == 1:
|
||||||
|
return "android:"
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def format_value(_type, _data, lookup_string=lambda ix: "<string>"):
|
||||||
|
if _type == TYPE_STRING:
|
||||||
|
return lookup_string(_data)
|
||||||
|
|
||||||
|
elif _type == TYPE_ATTRIBUTE:
|
||||||
|
return "?%s%08X" % (getPackage(_data), _data)
|
||||||
|
|
||||||
|
elif _type == TYPE_REFERENCE:
|
||||||
|
return "@%s%08X" % (getPackage(_data), _data)
|
||||||
|
|
||||||
|
elif _type == TYPE_FLOAT:
|
||||||
|
return "%f" % unpack("=f", pack("=L", _data))[0]
|
||||||
|
|
||||||
|
elif _type == TYPE_INT_HEX:
|
||||||
|
return "0x%08X" % _data
|
||||||
|
|
||||||
|
elif _type == TYPE_INT_BOOLEAN:
|
||||||
|
if _data == 0:
|
||||||
|
return "false"
|
||||||
|
return "true"
|
||||||
|
|
||||||
|
elif _type == TYPE_DIMENSION:
|
||||||
|
return "%f%s" % (complexToFloat(_data), DIMENSION_UNITS[_data & COMPLEX_UNIT_MASK])
|
||||||
|
|
||||||
|
elif _type == TYPE_FRACTION:
|
||||||
|
return "%f%s" % (complexToFloat(_data) * 100, FRACTION_UNITS[_data & COMPLEX_UNIT_MASK])
|
||||||
|
|
||||||
|
elif _type >= TYPE_FIRST_COLOR_INT and _type <= TYPE_LAST_COLOR_INT:
|
||||||
|
return "#%08X" % _data
|
||||||
|
|
||||||
|
elif _type >= TYPE_FIRST_INT and _type <= TYPE_LAST_INT:
|
||||||
|
return "%d" % long2int(_data)
|
||||||
|
|
||||||
|
return "<0x%X, type 0x%02X>" % (_data, _type)
|
||||||
|
|
||||||
|
|
||||||
|
class AXMLPrinter(object):
|
||||||
|
|
||||||
|
def __init__(self, raw_buff):
|
||||||
|
self.axml = AXMLParser(raw_buff)
|
||||||
|
self.xmlns = False
|
||||||
|
|
||||||
|
self.buff = u''
|
||||||
|
|
||||||
|
while True and self.axml.is_valid():
|
||||||
|
_type = self.axml.next()
|
||||||
|
|
||||||
|
if _type == START_DOCUMENT:
|
||||||
|
self.buff += u'<?xml version="1.0" encoding="utf-8"?>\n'
|
||||||
|
elif _type == START_TAG:
|
||||||
|
self.buff += u'<' + self.getPrefix(self.axml.getPrefix(
|
||||||
|
)) + self.axml.getName() + u'\n'
|
||||||
|
self.buff += self.axml.getXMLNS()
|
||||||
|
|
||||||
|
for i in range(0, self.axml.getAttributeCount()):
|
||||||
|
self.buff += "%s%s=\"%s\"\n" % (
|
||||||
|
self.getPrefix(
|
||||||
|
self.axml.getAttributePrefix(i)),
|
||||||
|
self.axml.getAttributeName(i),
|
||||||
|
self._escape(self.getAttributeValue(i)))
|
||||||
|
|
||||||
|
self.buff += u'>\n'
|
||||||
|
|
||||||
|
elif _type == END_TAG:
|
||||||
|
self.buff += "</%s%s>\n" % (
|
||||||
|
self.getPrefix(self.axml.getPrefix()), self.axml.getName())
|
||||||
|
|
||||||
|
elif _type == TEXT:
|
||||||
|
self.buff += "%s\n" % self.axml.getText()
|
||||||
|
|
||||||
|
elif _type == END_DOCUMENT:
|
||||||
|
break
|
||||||
|
|
||||||
|
# pleed patch
|
||||||
|
def _escape(self, s):
|
||||||
|
s = s.replace("&", "&")
|
||||||
|
s = s.replace('"', """)
|
||||||
|
s = s.replace("'", "'")
|
||||||
|
s = s.replace("<", "<")
|
||||||
|
s = s.replace(">", ">")
|
||||||
|
return escape(s)
|
||||||
|
|
||||||
|
def get_buff(self):
|
||||||
|
return self.buff.encode('utf-8')
|
||||||
|
|
||||||
|
def get_xml(self):
|
||||||
|
return minidom.parseString(self.get_buff()).toprettyxml(
|
||||||
|
encoding="utf-8")
|
||||||
|
|
||||||
|
def get_xml_obj(self):
|
||||||
|
return minidom.parseString(self.get_buff())
|
||||||
|
|
||||||
|
def getPrefix(self, prefix):
|
||||||
|
if prefix is None or len(prefix) == 0:
|
||||||
|
return u''
|
||||||
|
|
||||||
|
return prefix + u':'
|
||||||
|
|
||||||
|
def getAttributeValue(self, index):
|
||||||
|
_type = self.axml.getAttributeValueType(index)
|
||||||
|
_data = self.axml.getAttributeValueData(index)
|
||||||
|
|
||||||
|
return format_value(_type, _data, lambda _: self.axml.getAttributeValue(index))
|
||||||
|
|
||||||
|
|
||||||
|
class SV(object):
|
||||||
|
|
||||||
|
def __init__(self, size, buff):
|
||||||
|
self.__size = size
|
||||||
|
self.__value = unpack(self.__size, buff)[0]
|
||||||
|
|
||||||
|
def _get(self):
|
||||||
|
return pack(self.__size, self.__value)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "0x%x" % self.__value
|
||||||
|
|
||||||
|
def __int__(self):
|
||||||
|
return self.__value
|
||||||
|
|
||||||
|
def get_value_buff(self):
|
||||||
|
return self._get()
|
||||||
|
|
||||||
|
def get_value(self):
|
||||||
|
return self.__value
|
||||||
|
|
||||||
|
def set_value(self, attr):
|
||||||
|
self.__value = attr
|
||||||
|
|
||||||
|
|
||||||
|
class SVs(object):
|
||||||
|
|
||||||
|
def __init__(self, size, ntuple, buff):
|
||||||
|
self.__size = size
|
||||||
|
|
||||||
|
self.__value = ntuple._make(unpack(self.__size, buff))
|
||||||
|
|
||||||
|
def _get(self):
|
||||||
|
l = []
|
||||||
|
for i in self.__value._fields:
|
||||||
|
l.append(getattr(self.__value, i))
|
||||||
|
return pack(self.__size, *l)
|
||||||
|
|
||||||
|
def _export(self):
|
||||||
|
return [x for x in self.__value._fields]
|
||||||
|
|
||||||
|
def get_value_buff(self):
|
||||||
|
return self._get()
|
||||||
|
|
||||||
|
def get_value(self):
|
||||||
|
return self.__value
|
||||||
|
|
||||||
|
def set_value(self, attr):
|
||||||
|
self.__value = self.__value._replace(**attr)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.__value.__str__()
|
||||||
|
|
||||||
|
|
||||||
|
class BuffHandle(object):
|
||||||
|
|
||||||
|
def __init__(self, buff):
|
||||||
|
self.__buff = buff
|
||||||
|
self.__idx = 0
|
||||||
|
|
||||||
|
def size(self):
|
||||||
|
return len(self.__buff)
|
||||||
|
|
||||||
|
def set_idx(self, idx):
|
||||||
|
self.__idx = idx
|
||||||
|
|
||||||
|
def get_idx(self):
|
||||||
|
return self.__idx
|
||||||
|
|
||||||
|
def readNullString(self, size):
|
||||||
|
data = self.read(size)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def read_b(self, size):
|
||||||
|
return self.__buff[self.__idx:self.__idx + size]
|
||||||
|
|
||||||
|
def read_at(self, offset, size):
|
||||||
|
return self.__buff[offset:offset + size]
|
||||||
|
|
||||||
|
def read(self, size):
|
||||||
|
if isinstance(size, SV):
|
||||||
|
size = size.value
|
||||||
|
|
||||||
|
buff = self.__buff[self.__idx:self.__idx + size]
|
||||||
|
self.__idx += size
|
||||||
|
|
||||||
|
return buff
|
||||||
|
|
||||||
|
def end(self):
|
||||||
|
return self.__idx == len(self.__buff)
|
||||||
|
|
||||||
|
|
||||||
|
class Buff(object):
|
||||||
|
|
||||||
|
def __init__(self, offset, buff):
|
||||||
|
self.offset = offset
|
||||||
|
self.buff = buff
|
||||||
|
|
||||||
|
self.size = len(buff)
|
||||||
|
|
||||||
|
|
||||||
|
def long2int(l):
|
||||||
|
if l > 0x7fffffff:
|
||||||
|
l = (0x7fffffff & l) - 0x80000000
|
||||||
|
return l
|
50
build.gradle
Normal file
50
build.gradle
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
ext.kotlin_version = '1.8.22'
|
||||||
|
|
||||||
|
println "\n\n\n"
|
||||||
|
println '当前选择版本 Version Name:'+ version_name
|
||||||
|
println '当前选择版本 Version Code:'+ Integer.valueOf(version_code)
|
||||||
|
println "\n\n\n"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
mavenLocal()
|
||||||
|
jcenter()
|
||||||
|
google()
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/public' }
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
maven { url 'https://repo1.maven.org/maven2/' }
|
||||||
|
maven { url 'https://raw.githubusercontent.com/martinloren/AabResGuard/mvn-repo' }
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||||
|
// aRouter
|
||||||
|
classpath "com.alibaba:arouter-register:1.0.2"
|
||||||
|
//realm 数据库插件
|
||||||
|
classpath "io.realm:realm-gradle-plugin:10.16.1"
|
||||||
|
// android 资源混淆插件
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
classpath 'com.tencent.vasdolly:plugin:3.0.6'
|
||||||
|
|
||||||
|
classpath "com.bytedance.android:aabresguard-plugin:0.1.10"
|
||||||
|
classpath "com.github.liujingxing:XmlClassGuard:1.2.6"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
google()
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/public' }
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
maven { url 'https://repo1.maven.org/maven2/' }
|
||||||
|
}
|
||||||
|
//网络慢的话就去 https://maven.aliyun.com/mvn/view 里面找个代理的仓库。
|
||||||
|
}
|
||||||
|
|
||||||
|
task clean(type: Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
1
channel.txt
Normal file
1
channel.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
official
|
39
gradle.properties
Normal file
39
gradle.properties
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Project-wide Gradle settings.
|
||||||
|
# IDE (e.g. Android Studio) users:
|
||||||
|
# Gradle settings configured through the IDE *will override*
|
||||||
|
# any settings specified in this file.
|
||||||
|
# For more details on how to configure your build environment visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
org.gradle.jvmargs=-Xmx4096M -Dkotlin.daemon.jvm.options\="-Xmx4096M" -XX\:MaxMetaspaceSize\=4096m
|
||||||
|
|
||||||
|
org.gradle.daemon=true
|
||||||
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
|
# org.gradle.parallel=true
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
||||||
|
android.enableResourceOptimizations=false
|
||||||
|
android.injected.testOnly=false
|
||||||
|
# mob
|
||||||
|
MobSDK.spEdition=FP
|
||||||
|
|
||||||
|
minify_enabled=false
|
||||||
|
|
||||||
|
# 是否隔离模式:换包名、换签名、隐藏部分SDK-KEY信息、去掉部分SDK(Google相关)
|
||||||
|
isolation_mode=true
|
||||||
|
|
||||||
|
channel_file=channel.txt
|
||||||
|
CRASHLYTICS_COLLECTION_ENABLED=false
|
||||||
|
|
||||||
|
COMPILE_SDK_VERSION=34
|
||||||
|
MIN_SDK_VERSION=21
|
||||||
|
TARGET_SDK_VERSION=34
|
||||||
|
|
||||||
|
version_name=1.0.26
|
||||||
|
version_code=42
|
||||||
|
|
||||||
|
#systemProp.https.proxyHost=127.0.0.1
|
||||||
|
#systemProp.https.proxyPort=7890
|
160
gradlew
vendored
Normal file
160
gradlew
vendored
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn ( ) {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die ( ) {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||||
|
function splitJvmOpts() {
|
||||||
|
JVM_OPTS=("$@")
|
||||||
|
}
|
||||||
|
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||||
|
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||||
|
|
||||||
|
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
90
gradlew.bat
vendored
Normal file
90
gradlew.bat
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS=
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windowz variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
goto execute
|
||||||
|
|
||||||
|
:4NT_args
|
||||||
|
@rem Get arguments from the 4NT Shell from JP Software
|
||||||
|
set CMD_LINE_ARGS=%$
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
8
local.properties
Normal file
8
local.properties
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
## This file must *NOT* be checked into Version Control Systems,
|
||||||
|
# as it contains information specific to your local configuration.
|
||||||
|
#
|
||||||
|
# Location of the SDK. This is only used by Gradle.
|
||||||
|
# For customization when using a Version Control System, please read the
|
||||||
|
# header note.
|
||||||
|
#Mon Feb 26 14:07:21 CST 2024
|
||||||
|
sdk.dir=/Users/zhanglaiman/Library/Android/sdk
|
79
mode.json
Normal file
79
mode.json
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "success",
|
||||||
|
"data": {
|
||||||
|
"bigList": [],
|
||||||
|
"customChargeProd": [],
|
||||||
|
"defaultPay": 2,
|
||||||
|
"defaultPayH5": 2,
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"chargeProdId": "coin_charge_01",
|
||||||
|
"prodName": "7000 Coins",
|
||||||
|
"money": 1.0,
|
||||||
|
"giftGoldNum": 0,
|
||||||
|
"channel": 1,
|
||||||
|
"seqNo": 1,
|
||||||
|
"chargeGoldNum": 7000,
|
||||||
|
"currencySign": "USD",
|
||||||
|
"payChannel": "google_play_billing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chargeProdId": "coin_charge_02",
|
||||||
|
"prodName": "70000 Coins",
|
||||||
|
"money": 10.0,
|
||||||
|
"giftGoldNum": 0,
|
||||||
|
"channel": 1,
|
||||||
|
"seqNo": 2,
|
||||||
|
"chargeGoldNum": 70000,
|
||||||
|
"currencySign": "USD",
|
||||||
|
"payChannel": "google_play_billing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chargeProdId": "coin_charge_03",
|
||||||
|
"prodName": "140000 Coins",
|
||||||
|
"money": 20.0,
|
||||||
|
"giftGoldNum": 0,
|
||||||
|
"channel": 1,
|
||||||
|
"seqNo": 3,
|
||||||
|
"chargeGoldNum": 140000,
|
||||||
|
"currencySign": "USD",
|
||||||
|
"payChannel": "google_play_billing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chargeProdId": "coin_charge_04",
|
||||||
|
"prodName": "350000 Coins",
|
||||||
|
"money": 50.0,
|
||||||
|
"giftGoldNum": 0,
|
||||||
|
"channel": 1,
|
||||||
|
"seqNo": 4,
|
||||||
|
"chargeGoldNum": 350000,
|
||||||
|
"currencySign": "USD",
|
||||||
|
"payChannel": "google_play_billing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chargeProdId": "coin_charge_05",
|
||||||
|
"prodName": "560000 Coins",
|
||||||
|
"money": 80.0,
|
||||||
|
"giftGoldNum": 0,
|
||||||
|
"channel": 1,
|
||||||
|
"seqNo": 5,
|
||||||
|
"chargeGoldNum": 560000,
|
||||||
|
"currencySign": "USD",
|
||||||
|
"payChannel": "google_play_billing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chargeProdId": "coin_charge_06",
|
||||||
|
"prodName": "700000 Coins",
|
||||||
|
"money": 100.0,
|
||||||
|
"giftGoldNum": 0,
|
||||||
|
"channel": 1,
|
||||||
|
"seqNo": 6,
|
||||||
|
"chargeGoldNum": 700000,
|
||||||
|
"currencySign": "USD",
|
||||||
|
"payChannel": "google_play_billing"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"timestamp": 1751363110053
|
||||||
|
}
|
BIN
molistar.jks
Normal file
BIN
molistar.jks
Normal file
Binary file not shown.
BIN
molistar_debug.jks
Normal file
BIN
molistar_debug.jks
Normal file
Binary file not shown.
17
project.gradle
Normal file
17
project.gradle
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
ext {
|
||||||
|
isolationMode = Boolean.valueOf(isolation_mode)
|
||||||
|
println("是否隔离模式:" + isolationMode)
|
||||||
|
|
||||||
|
package_name = project.hasProperty('package_name') ? package_name
|
||||||
|
: (isolationMode ? 'com.example.gogo.none' : 'com.example.live')
|
||||||
|
println("applicationId is " + package_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isReleaseBuildType() {
|
||||||
|
for (String s : gradle.startParameter.taskNames) {
|
||||||
|
if (s.contains("Release") | s.contains("release")) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
52
readme.md
Normal file
52
readme.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# 初始化项目
|
||||||
|
命令行教学
|
||||||
|
```
|
||||||
|
git clone git@code.aliyun.com:qingxun/qx_android_client.git
|
||||||
|
```
|
||||||
|
|
||||||
|
# 拉取或推送
|
||||||
|
拉取
|
||||||
|
```
|
||||||
|
git subtree pull --prefix={dirName} {repoUrl} {branchName}
|
||||||
|
```
|
||||||
|
推送
|
||||||
|
```
|
||||||
|
git subtree push --prefix={dirName} {repoUrl} {branchName}
|
||||||
|
```
|
||||||
|
>{dirName} 为 core 、library 或者 nim_uikit
|
||||||
|
|
||||||
|
>{repoUrl} 为对应的子仓库地址
|
||||||
|
|
||||||
|
>{branchName} 为要拉取或者推送的分支名
|
||||||
|
|
||||||
|
## 指定渠道打包
|
||||||
|
```
|
||||||
|
java -jar packer-ng-2.0.0.jar generate --channels=yingyongbao --output=build/jiaku/apk --input=/Users/MadisonRong/dev/Android/erban-release/2.4.3/erban_client-release_aligned_signed-yingyongbao_243_jiagu_sign.apk
|
||||||
|
```
|
||||||
|
|
||||||
|
## python查看渠道信息
|
||||||
|
支持查看单个apk文件或者文件夹下的所有apk文件。
|
||||||
|
```
|
||||||
|
python packer-ng-v2.py xxxx.apk
|
||||||
|
```
|
||||||
|
|
||||||
|
##应用框架
|
||||||
|
- MVP(按照 <a href="https://blog.csdn.net/yulong0809/article/details/78622428">刘镓旗的博客</a> 的来封装)
|
||||||
|
- CoreEvent(yy的框架?有预料不到的bug)
|
||||||
|
- rxJava
|
||||||
|
|
||||||
|
##sdk的应用场景
|
||||||
|
- 声网(开闭麦),声网有关房间操作封装在RtcEngineManager
|
||||||
|
- 云信(朋友,粉丝,黑名单[房间,关系],队列,自定义消息,最近联系人,监听信息),云信有关房间的操作封装在IMNeteaseManager
|
||||||
|
|
||||||
|
##功能
|
||||||
|
- 礼物(GiftModel和GiftDialog包换获取数据和显示数据所有逻辑)
|
||||||
|
- 魔法(MagicModel,MagicDialog包换获取数据和显示数据所有逻辑)
|
||||||
|
- 座驾(商城,车库,CarActvity)
|
||||||
|
- 贵族(NobleUtil,NobleDataManager里面实现了贵族资源,权限的获取)
|
||||||
|
- 表情(FaceCoreImpl,下载和配置)
|
||||||
|
- 房间(房间设置,跳坑,上麦,下麦,锁坑,禁言,显示在MicroView和MicroViewAdapter,实现逻辑在AvRoomModel和AvRoomPresenter和ButtonItemFactory里面)
|
||||||
|
- 公屏(MessageView云信自定义消息的显示)
|
||||||
|
- 动画(帧动画[表情],属性动画[礼物],SVGA[座驾,房间背景,礼物特效,魔法])
|
||||||
|
- 统计(未完善,入口StatisticManager)
|
||||||
|
- 云信自定义信息(CustomAttachment和CustomAttachParser)
|
54
screenMatch.properties
Normal file
54
screenMatch.properties
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
############################################################################
|
||||||
|
# Start with '#' is annotate. #
|
||||||
|
# In front of '=' is key, cannot be modified. #
|
||||||
|
# More information to visit: #
|
||||||
|
# http://blog.csdn.net/fesdgasdgasdg/article/details/52325590 #
|
||||||
|
# http://download.csdn.net/detail/fesdgasdgasdg/9913744 #
|
||||||
|
# https://github.com/mengzhinan/PhoneScreenMatch #
|
||||||
|
############################################################################
|
||||||
|
#
|
||||||
|
# You need to refresh or reopen the project every time you modify the configuration,
|
||||||
|
# or you can't get the latest configuration parameters.
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
#
|
||||||
|
# Base dp value for screen match. Cut the screen into [base_dp] parts.
|
||||||
|
# Data type is double. System default value is 360.
|
||||||
|
# I advise you not to modify the value, be careful !!!!!!!!! _^_ *_*
|
||||||
|
base_dp=360
|
||||||
|
# Also need to match the phone screen of [match_dp].
|
||||||
|
# If you have another dp values.
|
||||||
|
# System default values is 240,320,384,392,400,410,411,480,533,592,600,640,662,720,768,800,811,820,960,961,1024,1280,1365
|
||||||
|
match_dp=
|
||||||
|
# If you not wanna to match dp values above. Write some above values here, append value with "," .
|
||||||
|
# For example: 811,961,1365
|
||||||
|
ignore_dp=
|
||||||
|
# They're not android module name. If has more<72><65>split with , Symbol.
|
||||||
|
# If you set, it will not show in SelectDialog.
|
||||||
|
# If you have, write here and append value with "," .
|
||||||
|
# For example: testLibrary,commonModule
|
||||||
|
# System default values is .gradle, gradle, .idea, build, .git
|
||||||
|
ignore_module_name=
|
||||||
|
# Use which module under the values/dimen.xml file to do the base file,
|
||||||
|
# and generated dimen.xml file store in this module?
|
||||||
|
# Default value is 'app'.
|
||||||
|
match_module=app
|
||||||
|
# Don't show select dialog again when use this plugin.
|
||||||
|
# System screen match will use the last selected module name or default module name.
|
||||||
|
# You can give value true or false. Default value is false.
|
||||||
|
not_show_dialog=false
|
||||||
|
# Do you want to generate the default example dimens.xml file?
|
||||||
|
# In path of .../projectName/screenMatch_example_dimens.xml, It does not affect your project code.
|
||||||
|
# You can give value true or false. Default value is false.
|
||||||
|
not_create_default_dimens=false
|
||||||
|
# Does the font scale the same size as the DP? May not be accuracy.
|
||||||
|
# You can give value true or false. Default value is true. Also need scaled.
|
||||||
|
is_match_font_sp=true
|
||||||
|
# Do you want to create values-wXXXdp folder or values-swXXXdp folder ?
|
||||||
|
# I suggest you create values-swXXXdp folder,
|
||||||
|
# because I had a problem when I was working on the horizontal screen adapter.
|
||||||
|
# values-swXXXdp folder can solve my problem.
|
||||||
|
# If you want create values-swXXXdp folder, set "create_values_sw_folder=true",
|
||||||
|
# otherwise set "create_values_sw_folder=true".
|
||||||
|
# Default values is true.
|
||||||
|
create_values_sw_folder=true
|
431
screenMatch_example_dimens.xml
Normal file
431
screenMatch_example_dimens.xml
Normal file
@@ -0,0 +1,431 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Your custom size defind by references, can be writted in anywhere, any module, any values/*.xml, for example: -->
|
||||||
|
<dimen name="card_common_margin_left">@dimen/dp_15</dimen>
|
||||||
|
|
||||||
|
<!-- dp and sp values, must be defind in this file! -->
|
||||||
|
<!-- view size,you can add if there is no one -->
|
||||||
|
<dimen name="dp_m_60">-60dp</dimen>
|
||||||
|
<dimen name="dp_m_30">-30dp</dimen>
|
||||||
|
<dimen name="dp_m_20">-20dp</dimen>
|
||||||
|
<dimen name="dp_m_12">-12dp</dimen>
|
||||||
|
<dimen name="dp_m_10">-10dp</dimen>
|
||||||
|
<dimen name="dp_m_8">-8dp</dimen>
|
||||||
|
<dimen name="dp_m_5">-5dp</dimen>
|
||||||
|
<dimen name="dp_m_2">-2dp</dimen>
|
||||||
|
<dimen name="dp_m_1">-1dp</dimen>
|
||||||
|
<dimen name="dp_0">0dp</dimen>
|
||||||
|
<dimen name="dp_0_1">0.1dp</dimen>
|
||||||
|
<dimen name="dp_0_5">0.5dp</dimen>
|
||||||
|
<dimen name="dp_1">1dp</dimen>
|
||||||
|
<dimen name="dp_1_5">1.5dp</dimen>
|
||||||
|
<dimen name="dp_2">2dp</dimen>
|
||||||
|
<dimen name="dp_2_5">2.5dp</dimen>
|
||||||
|
<dimen name="dp_3">3dp</dimen>
|
||||||
|
<dimen name="dp_3_5">3.5dp</dimen>
|
||||||
|
<dimen name="dp_4">4dp</dimen>
|
||||||
|
<dimen name="dp_4_5">4.5dp</dimen>
|
||||||
|
<dimen name="dp_5">5dp</dimen>
|
||||||
|
<dimen name="dp_6">6dp</dimen>
|
||||||
|
<dimen name="dp_7">7dp</dimen>
|
||||||
|
<dimen name="dp_7_5">7.5dp</dimen>
|
||||||
|
<dimen name="dp_8">8dp</dimen>
|
||||||
|
<dimen name="dp_9">9dp</dimen>
|
||||||
|
<dimen name="dp_10">10dp</dimen>
|
||||||
|
<dimen name="dp_11">11dp</dimen>
|
||||||
|
<dimen name="dp_12">12dp</dimen>
|
||||||
|
<dimen name="dp_13">13dp</dimen>
|
||||||
|
<dimen name="dp_14">14dp</dimen>
|
||||||
|
<dimen name="dp_15">15dp</dimen>
|
||||||
|
<dimen name="dp_16">16dp</dimen>
|
||||||
|
<dimen name="dp_17">17dp</dimen>
|
||||||
|
<dimen name="dp_18">18dp</dimen>
|
||||||
|
<dimen name="dp_19">19dp</dimen>
|
||||||
|
<dimen name="dp_20">20dp</dimen>
|
||||||
|
<dimen name="dp_21">21dp</dimen>
|
||||||
|
<dimen name="dp_22">22dp</dimen>
|
||||||
|
<dimen name="dp_23">23dp</dimen>
|
||||||
|
<dimen name="dp_24">24dp</dimen>
|
||||||
|
<dimen name="dp_25">25dp</dimen>
|
||||||
|
<dimen name="dp_26">26dp</dimen>
|
||||||
|
<dimen name="dp_27">27dp</dimen>
|
||||||
|
<dimen name="dp_28">28dp</dimen>
|
||||||
|
<dimen name="dp_29">29dp</dimen>
|
||||||
|
<dimen name="dp_30">30dp</dimen>
|
||||||
|
<dimen name="dp_31">31dp</dimen>
|
||||||
|
<dimen name="dp_32">32dp</dimen>
|
||||||
|
<dimen name="dp_33">33dp</dimen>
|
||||||
|
<dimen name="dp_34">34dp</dimen>
|
||||||
|
<dimen name="dp_35">35dp</dimen>
|
||||||
|
<dimen name="dp_36">36dp</dimen>
|
||||||
|
<dimen name="dp_37">37dp</dimen>
|
||||||
|
<dimen name="dp_38">38dp</dimen>
|
||||||
|
<dimen name="dp_39">39dp</dimen>
|
||||||
|
<dimen name="dp_40">40dp</dimen>
|
||||||
|
<dimen name="dp_41">41dp</dimen>
|
||||||
|
<dimen name="dp_42">42dp</dimen>
|
||||||
|
<dimen name="dp_43">43dp</dimen>
|
||||||
|
<dimen name="dp_44">44dp</dimen>
|
||||||
|
<dimen name="dp_45">45dp</dimen>
|
||||||
|
<dimen name="dp_46">46dp</dimen>
|
||||||
|
<dimen name="dp_47">47dp</dimen>
|
||||||
|
<dimen name="dp_48">48dp</dimen>
|
||||||
|
<dimen name="dp_49">49dp</dimen>
|
||||||
|
<dimen name="dp_50">50dp</dimen>
|
||||||
|
<dimen name="dp_51">51dp</dimen>
|
||||||
|
<dimen name="dp_52">52dp</dimen>
|
||||||
|
<dimen name="dp_53">53dp</dimen>
|
||||||
|
<dimen name="dp_54">54dp</dimen>
|
||||||
|
<dimen name="dp_55">55dp</dimen>
|
||||||
|
<dimen name="dp_56">56dp</dimen>
|
||||||
|
<dimen name="dp_57">57dp</dimen>
|
||||||
|
<dimen name="dp_58">58dp</dimen>
|
||||||
|
<dimen name="dp_59">59dp</dimen>
|
||||||
|
<dimen name="dp_60">60dp</dimen>
|
||||||
|
<dimen name="dp_61">61dp</dimen>
|
||||||
|
<dimen name="dp_62">62dp</dimen>
|
||||||
|
<dimen name="dp_63">63dp</dimen>
|
||||||
|
<dimen name="dp_64">64dp</dimen>
|
||||||
|
<dimen name="dp_65">65dp</dimen>
|
||||||
|
<dimen name="dp_66">66dp</dimen>
|
||||||
|
<dimen name="dp_67">67dp</dimen>
|
||||||
|
<dimen name="dp_68">68dp</dimen>
|
||||||
|
<dimen name="dp_69">69dp</dimen>
|
||||||
|
<dimen name="dp_70">70dp</dimen>
|
||||||
|
<dimen name="dp_71">71dp</dimen>
|
||||||
|
<dimen name="dp_72">72dp</dimen>
|
||||||
|
<dimen name="dp_73">73dp</dimen>
|
||||||
|
<dimen name="dp_74">74dp</dimen>
|
||||||
|
<dimen name="dp_75">75dp</dimen>
|
||||||
|
<dimen name="dp_76">76dp</dimen>
|
||||||
|
<dimen name="dp_77">77dp</dimen>
|
||||||
|
<dimen name="dp_78">78dp</dimen>
|
||||||
|
<dimen name="dp_79">79dp</dimen>
|
||||||
|
<dimen name="dp_80">80dp</dimen>
|
||||||
|
<dimen name="dp_81">81dp</dimen>
|
||||||
|
<dimen name="dp_82">82dp</dimen>
|
||||||
|
<dimen name="dp_83">83dp</dimen>
|
||||||
|
<dimen name="dp_84">84dp</dimen>
|
||||||
|
<dimen name="dp_85">85dp</dimen>
|
||||||
|
<dimen name="dp_86">86dp</dimen>
|
||||||
|
<dimen name="dp_87">87dp</dimen>
|
||||||
|
<dimen name="dp_88">88dp</dimen>
|
||||||
|
<dimen name="dp_89">89dp</dimen>
|
||||||
|
<dimen name="dp_90">90dp</dimen>
|
||||||
|
<dimen name="dp_91">91dp</dimen>
|
||||||
|
<dimen name="dp_92">92dp</dimen>
|
||||||
|
<dimen name="dp_93">93dp</dimen>
|
||||||
|
<dimen name="dp_94">94dp</dimen>
|
||||||
|
<dimen name="dp_95">95dp</dimen>
|
||||||
|
<dimen name="dp_96">96dp</dimen>
|
||||||
|
<dimen name="dp_97">97dp</dimen>
|
||||||
|
<dimen name="dp_98">98dp</dimen>
|
||||||
|
<dimen name="dp_99">99dp</dimen>
|
||||||
|
<dimen name="dp_100">100dp</dimen>
|
||||||
|
<dimen name="dp_101">101dp</dimen>
|
||||||
|
<dimen name="dp_102">102dp</dimen>
|
||||||
|
<dimen name="dp_103">103dp</dimen>
|
||||||
|
<dimen name="dp_104">104dp</dimen>
|
||||||
|
<dimen name="dp_104_5">104.5dp</dimen>
|
||||||
|
<dimen name="dp_105">105dp</dimen>
|
||||||
|
<dimen name="dp_106">106dp</dimen>
|
||||||
|
<dimen name="dp_107">107dp</dimen>
|
||||||
|
<dimen name="dp_108">108dp</dimen>
|
||||||
|
<dimen name="dp_109">109dp</dimen>
|
||||||
|
<dimen name="dp_110">110dp</dimen>
|
||||||
|
<dimen name="dp_111">111dp</dimen>
|
||||||
|
<dimen name="dp_112">112dp</dimen>
|
||||||
|
<dimen name="dp_113">113dp</dimen>
|
||||||
|
<dimen name="dp_114">114dp</dimen>
|
||||||
|
<dimen name="dp_115">115dp</dimen>
|
||||||
|
<dimen name="dp_116">116dp</dimen>
|
||||||
|
<dimen name="dp_117">117dp</dimen>
|
||||||
|
<dimen name="dp_118">118dp</dimen>
|
||||||
|
<dimen name="dp_119">119dp</dimen>
|
||||||
|
<dimen name="dp_120">120dp</dimen>
|
||||||
|
<dimen name="dp_121">121dp</dimen>
|
||||||
|
<dimen name="dp_122">122dp</dimen>
|
||||||
|
<dimen name="dp_123">123dp</dimen>
|
||||||
|
<dimen name="dp_124">124dp</dimen>
|
||||||
|
<dimen name="dp_125">125dp</dimen>
|
||||||
|
<dimen name="dp_126">126dp</dimen>
|
||||||
|
<dimen name="dp_127">127dp</dimen>
|
||||||
|
<dimen name="dp_128">128dp</dimen>
|
||||||
|
<dimen name="dp_129">129dp</dimen>
|
||||||
|
<dimen name="dp_130">130dp</dimen>
|
||||||
|
<dimen name="dp_131">131dp</dimen>
|
||||||
|
<dimen name="dp_132">132dp</dimen>
|
||||||
|
<dimen name="dp_133">133dp</dimen>
|
||||||
|
<dimen name="dp_134">134dp</dimen>
|
||||||
|
<dimen name="dp_134_5">134.5dp</dimen>
|
||||||
|
<dimen name="dp_135">135dp</dimen>
|
||||||
|
<dimen name="dp_136">136dp</dimen>
|
||||||
|
<dimen name="dp_137">137dp</dimen>
|
||||||
|
<dimen name="dp_138">138dp</dimen>
|
||||||
|
<dimen name="dp_139">139dp</dimen>
|
||||||
|
<dimen name="dp_140">140dp</dimen>
|
||||||
|
<dimen name="dp_141">141dp</dimen>
|
||||||
|
<dimen name="dp_142">142dp</dimen>
|
||||||
|
<dimen name="dp_143">143dp</dimen>
|
||||||
|
<dimen name="dp_144">144dp</dimen>
|
||||||
|
<dimen name="dp_145">145dp</dimen>
|
||||||
|
<dimen name="dp_146">146dp</dimen>
|
||||||
|
<dimen name="dp_147">147dp</dimen>
|
||||||
|
<dimen name="dp_148">148dp</dimen>
|
||||||
|
<dimen name="dp_149">149dp</dimen>
|
||||||
|
<dimen name="dp_150">150dp</dimen>
|
||||||
|
<dimen name="dp_151">151dp</dimen>
|
||||||
|
<dimen name="dp_152">152dp</dimen>
|
||||||
|
<dimen name="dp_153">153dp</dimen>
|
||||||
|
<dimen name="dp_154">154dp</dimen>
|
||||||
|
<dimen name="dp_155">155dp</dimen>
|
||||||
|
<dimen name="dp_156">156dp</dimen>
|
||||||
|
<dimen name="dp_157">157dp</dimen>
|
||||||
|
<dimen name="dp_158">158dp</dimen>
|
||||||
|
<dimen name="dp_159">159dp</dimen>
|
||||||
|
<dimen name="dp_160">160dp</dimen>
|
||||||
|
<dimen name="dp_161">161dp</dimen>
|
||||||
|
<dimen name="dp_162">162dp</dimen>
|
||||||
|
<dimen name="dp_163">163dp</dimen>
|
||||||
|
<dimen name="dp_164">164dp</dimen>
|
||||||
|
<dimen name="dp_165">165dp</dimen>
|
||||||
|
<dimen name="dp_166">166dp</dimen>
|
||||||
|
<dimen name="dp_167">167dp</dimen>
|
||||||
|
<dimen name="dp_168">168dp</dimen>
|
||||||
|
<dimen name="dp_169">169dp</dimen>
|
||||||
|
<dimen name="dp_170">170dp</dimen>
|
||||||
|
<dimen name="dp_171">171dp</dimen>
|
||||||
|
<dimen name="dp_172">172dp</dimen>
|
||||||
|
<dimen name="dp_173">173dp</dimen>
|
||||||
|
<dimen name="dp_174">174dp</dimen>
|
||||||
|
<dimen name="dp_175">175dp</dimen>
|
||||||
|
<dimen name="dp_176">176dp</dimen>
|
||||||
|
<dimen name="dp_177">177dp</dimen>
|
||||||
|
<dimen name="dp_178">178dp</dimen>
|
||||||
|
<dimen name="dp_179">179dp</dimen>
|
||||||
|
<dimen name="dp_180">180dp</dimen>
|
||||||
|
<dimen name="dp_181">181dp</dimen>
|
||||||
|
<dimen name="dp_182">182dp</dimen>
|
||||||
|
<dimen name="dp_183">183dp</dimen>
|
||||||
|
<dimen name="dp_184">184dp</dimen>
|
||||||
|
<dimen name="dp_185">185dp</dimen>
|
||||||
|
<dimen name="dp_186">186dp</dimen>
|
||||||
|
<dimen name="dp_187">187dp</dimen>
|
||||||
|
<dimen name="dp_188">188dp</dimen>
|
||||||
|
<dimen name="dp_189">189dp</dimen>
|
||||||
|
<dimen name="dp_190">190dp</dimen>
|
||||||
|
<dimen name="dp_191">191dp</dimen>
|
||||||
|
<dimen name="dp_191_25">191.25dp</dimen>
|
||||||
|
<dimen name="dp_192">192dp</dimen>
|
||||||
|
<dimen name="dp_193">193dp</dimen>
|
||||||
|
<dimen name="dp_194">194dp</dimen>
|
||||||
|
<dimen name="dp_195">195dp</dimen>
|
||||||
|
<dimen name="dp_196">196dp</dimen>
|
||||||
|
<dimen name="dp_197">197dp</dimen>
|
||||||
|
<dimen name="dp_198">198dp</dimen>
|
||||||
|
<dimen name="dp_199">199dp</dimen>
|
||||||
|
<dimen name="dp_200">200dp</dimen>
|
||||||
|
<dimen name="dp_201">201dp</dimen>
|
||||||
|
<dimen name="dp_202">202dp</dimen>
|
||||||
|
<dimen name="dp_203">203dp</dimen>
|
||||||
|
<dimen name="dp_204">204dp</dimen>
|
||||||
|
<dimen name="dp_205">205dp</dimen>
|
||||||
|
<dimen name="dp_206">206dp</dimen>
|
||||||
|
<dimen name="dp_207">207dp</dimen>
|
||||||
|
<dimen name="dp_208">208dp</dimen>
|
||||||
|
<dimen name="dp_209">209dp</dimen>
|
||||||
|
<dimen name="dp_210">210dp</dimen>
|
||||||
|
<dimen name="dp_211">211dp</dimen>
|
||||||
|
<dimen name="dp_212">212dp</dimen>
|
||||||
|
<dimen name="dp_213">213dp</dimen>
|
||||||
|
<dimen name="dp_214">214dp</dimen>
|
||||||
|
<dimen name="dp_215">215dp</dimen>
|
||||||
|
<dimen name="dp_216">216dp</dimen>
|
||||||
|
<dimen name="dp_217">217dp</dimen>
|
||||||
|
<dimen name="dp_218">218dp</dimen>
|
||||||
|
<dimen name="dp_219">219dp</dimen>
|
||||||
|
<dimen name="dp_220">220dp</dimen>
|
||||||
|
<dimen name="dp_221">221dp</dimen>
|
||||||
|
<dimen name="dp_222">222dp</dimen>
|
||||||
|
<dimen name="dp_223">223dp</dimen>
|
||||||
|
<dimen name="dp_224">224dp</dimen>
|
||||||
|
<dimen name="dp_225">225dp</dimen>
|
||||||
|
<dimen name="dp_226">226dp</dimen>
|
||||||
|
<dimen name="dp_227">227dp</dimen>
|
||||||
|
<dimen name="dp_228">228dp</dimen>
|
||||||
|
<dimen name="dp_229">229dp</dimen>
|
||||||
|
<dimen name="dp_230">230dp</dimen>
|
||||||
|
<dimen name="dp_231">231dp</dimen>
|
||||||
|
<dimen name="dp_232">232dp</dimen>
|
||||||
|
<dimen name="dp_233">233dp</dimen>
|
||||||
|
<dimen name="dp_234">234dp</dimen>
|
||||||
|
<dimen name="dp_235">235dp</dimen>
|
||||||
|
<dimen name="dp_236">236dp</dimen>
|
||||||
|
<dimen name="dp_237">237dp</dimen>
|
||||||
|
<dimen name="dp_238">238dp</dimen>
|
||||||
|
<dimen name="dp_239">239dp</dimen>
|
||||||
|
<dimen name="dp_240">240dp</dimen>
|
||||||
|
<dimen name="dp_241">241dp</dimen>
|
||||||
|
<dimen name="dp_242">242dp</dimen>
|
||||||
|
<dimen name="dp_243">243dp</dimen>
|
||||||
|
<dimen name="dp_244">244dp</dimen>
|
||||||
|
<dimen name="dp_245">245dp</dimen>
|
||||||
|
<dimen name="dp_246">246dp</dimen>
|
||||||
|
<dimen name="dp_247">247dp</dimen>
|
||||||
|
<dimen name="dp_248">248dp</dimen>
|
||||||
|
<dimen name="dp_249">249dp</dimen>
|
||||||
|
<dimen name="dp_250">250dp</dimen>
|
||||||
|
<dimen name="dp_251">251dp</dimen>
|
||||||
|
<dimen name="dp_252">252dp</dimen>
|
||||||
|
<dimen name="dp_253">253dp</dimen>
|
||||||
|
<dimen name="dp_254">254dp</dimen>
|
||||||
|
<dimen name="dp_255">255dp</dimen>
|
||||||
|
<dimen name="dp_256">256dp</dimen>
|
||||||
|
<dimen name="dp_257">257dp</dimen>
|
||||||
|
<dimen name="dp_258">258dp</dimen>
|
||||||
|
<dimen name="dp_259">259dp</dimen>
|
||||||
|
<dimen name="dp_260">260dp</dimen>
|
||||||
|
<dimen name="dp_261">261dp</dimen>
|
||||||
|
<dimen name="dp_262">262dp</dimen>
|
||||||
|
<dimen name="dp_263">263dp</dimen>
|
||||||
|
<dimen name="dp_264">264dp</dimen>
|
||||||
|
<dimen name="dp_265">265dp</dimen>
|
||||||
|
<dimen name="dp_266">266dp</dimen>
|
||||||
|
<dimen name="dp_267">267dp</dimen>
|
||||||
|
<dimen name="dp_268">268dp</dimen>
|
||||||
|
<dimen name="dp_269">269dp</dimen>
|
||||||
|
<dimen name="dp_270">270dp</dimen>
|
||||||
|
<dimen name="dp_271">271dp</dimen>
|
||||||
|
<dimen name="dp_272">272dp</dimen>
|
||||||
|
<dimen name="dp_273">273dp</dimen>
|
||||||
|
<dimen name="dp_274">274dp</dimen>
|
||||||
|
<dimen name="dp_275">275dp</dimen>
|
||||||
|
<dimen name="dp_276">276dp</dimen>
|
||||||
|
<dimen name="dp_277">277dp</dimen>
|
||||||
|
<dimen name="dp_278">278dp</dimen>
|
||||||
|
<dimen name="dp_279">279dp</dimen>
|
||||||
|
<dimen name="dp_280">280dp</dimen>
|
||||||
|
<dimen name="dp_281">281dp</dimen>
|
||||||
|
<dimen name="dp_282">282dp</dimen>
|
||||||
|
<dimen name="dp_283">283dp</dimen>
|
||||||
|
<dimen name="dp_284">284dp</dimen>
|
||||||
|
<dimen name="dp_285">285dp</dimen>
|
||||||
|
<dimen name="dp_286">286dp</dimen>
|
||||||
|
<dimen name="dp_287">287dp</dimen>
|
||||||
|
<dimen name="dp_288">288dp</dimen>
|
||||||
|
<dimen name="dp_289">289dp</dimen>
|
||||||
|
<dimen name="dp_290">290dp</dimen>
|
||||||
|
<dimen name="dp_291">291dp</dimen>
|
||||||
|
<dimen name="dp_292">292dp</dimen>
|
||||||
|
<dimen name="dp_293">293dp</dimen>
|
||||||
|
<dimen name="dp_294">294dp</dimen>
|
||||||
|
<dimen name="dp_295">295dp</dimen>
|
||||||
|
<dimen name="dp_296">296dp</dimen>
|
||||||
|
<dimen name="dp_297">297dp</dimen>
|
||||||
|
<dimen name="dp_298">298dp</dimen>
|
||||||
|
<dimen name="dp_299">299dp</dimen>
|
||||||
|
<dimen name="dp_300">300dp</dimen>
|
||||||
|
<dimen name="dp_301">301dp</dimen>
|
||||||
|
<dimen name="dp_302">302dp</dimen>
|
||||||
|
<dimen name="dp_303">303dp</dimen>
|
||||||
|
<dimen name="dp_304">304dp</dimen>
|
||||||
|
<dimen name="dp_305">305dp</dimen>
|
||||||
|
<dimen name="dp_306">306dp</dimen>
|
||||||
|
<dimen name="dp_307">307dp</dimen>
|
||||||
|
<dimen name="dp_308">308dp</dimen>
|
||||||
|
<dimen name="dp_309">309dp</dimen>
|
||||||
|
<dimen name="dp_310">310dp</dimen>
|
||||||
|
<dimen name="dp_311">311dp</dimen>
|
||||||
|
<dimen name="dp_312">312dp</dimen>
|
||||||
|
<dimen name="dp_313">313dp</dimen>
|
||||||
|
<dimen name="dp_314">314dp</dimen>
|
||||||
|
<dimen name="dp_315">315dp</dimen>
|
||||||
|
<dimen name="dp_316">316dp</dimen>
|
||||||
|
<dimen name="dp_317">317dp</dimen>
|
||||||
|
<dimen name="dp_318">318dp</dimen>
|
||||||
|
<dimen name="dp_319">319dp</dimen>
|
||||||
|
<dimen name="dp_320">320dp</dimen>
|
||||||
|
<dimen name="dp_321">321dp</dimen>
|
||||||
|
<dimen name="dp_322">322dp</dimen>
|
||||||
|
<dimen name="dp_323">323dp</dimen>
|
||||||
|
<dimen name="dp_324">324dp</dimen>
|
||||||
|
<dimen name="dp_325">325dp</dimen>
|
||||||
|
<dimen name="dp_326">326dp</dimen>
|
||||||
|
<dimen name="dp_327">327dp</dimen>
|
||||||
|
<dimen name="dp_328">328dp</dimen>
|
||||||
|
<dimen name="dp_329">329dp</dimen>
|
||||||
|
<dimen name="dp_330">330dp</dimen>
|
||||||
|
<dimen name="dp_331">331dp</dimen>
|
||||||
|
<dimen name="dp_332">332dp</dimen>
|
||||||
|
<dimen name="dp_333">333dp</dimen>
|
||||||
|
<dimen name="dp_334">334dp</dimen>
|
||||||
|
<dimen name="dp_335">335dp</dimen>
|
||||||
|
<dimen name="dp_336">336dp</dimen>
|
||||||
|
<dimen name="dp_337">337dp</dimen>
|
||||||
|
<dimen name="dp_338">338dp</dimen>
|
||||||
|
<dimen name="dp_339">339dp</dimen>
|
||||||
|
<dimen name="dp_340">340dp</dimen>
|
||||||
|
<dimen name="dp_341">341dp</dimen>
|
||||||
|
<dimen name="dp_342">342dp</dimen>
|
||||||
|
<dimen name="dp_343">343dp</dimen>
|
||||||
|
<dimen name="dp_344">344dp</dimen>
|
||||||
|
<dimen name="dp_345">345dp</dimen>
|
||||||
|
<dimen name="dp_346">346dp</dimen>
|
||||||
|
<dimen name="dp_347">347dp</dimen>
|
||||||
|
<dimen name="dp_348">348dp</dimen>
|
||||||
|
<dimen name="dp_349">349dp</dimen>
|
||||||
|
<dimen name="dp_350">350dp</dimen>
|
||||||
|
<dimen name="dp_351">351dp</dimen>
|
||||||
|
<dimen name="dp_352">352dp</dimen>
|
||||||
|
<dimen name="dp_353">353dp</dimen>
|
||||||
|
<dimen name="dp_354">354dp</dimen>
|
||||||
|
<dimen name="dp_355">355dp</dimen>
|
||||||
|
<dimen name="dp_356">356dp</dimen>
|
||||||
|
<dimen name="dp_357">357dp</dimen>
|
||||||
|
<dimen name="dp_358">358dp</dimen>
|
||||||
|
<dimen name="dp_359">359dp</dimen>
|
||||||
|
<dimen name="dp_360">360dp</dimen>
|
||||||
|
<dimen name="dp_365">365dp</dimen>
|
||||||
|
<dimen name="dp_370">370dp</dimen>
|
||||||
|
<dimen name="dp_400">400dp</dimen>
|
||||||
|
<dimen name="dp_410">410dp</dimen>
|
||||||
|
<dimen name="dp_422">422dp</dimen>
|
||||||
|
<dimen name="dp_472">472dp</dimen>
|
||||||
|
<dimen name="dp_500">500dp</dimen>
|
||||||
|
<dimen name="dp_600">600dp</dimen>
|
||||||
|
<dimen name="dp_640">640dp</dimen>
|
||||||
|
<dimen name="dp_720">720dp</dimen>
|
||||||
|
|
||||||
|
<!-- font size,you can add if there is no one -->
|
||||||
|
<dimen name="sp_6">6sp</dimen>
|
||||||
|
<dimen name="sp_7">7sp</dimen>
|
||||||
|
<dimen name="sp_8">8sp</dimen>
|
||||||
|
<dimen name="sp_9">9sp</dimen>
|
||||||
|
<dimen name="sp_10">10sp</dimen>
|
||||||
|
<dimen name="sp_11">11sp</dimen>
|
||||||
|
<dimen name="sp_12">12sp</dimen>
|
||||||
|
<dimen name="sp_13">13sp</dimen>
|
||||||
|
<dimen name="sp_14">14sp</dimen>
|
||||||
|
<dimen name="sp_15">15sp</dimen>
|
||||||
|
<dimen name="sp_16">16sp</dimen>
|
||||||
|
<dimen name="sp_17">17sp</dimen>
|
||||||
|
<dimen name="sp_18">18sp</dimen>
|
||||||
|
<dimen name="sp_19">19sp</dimen>
|
||||||
|
<dimen name="sp_20">20sp</dimen>
|
||||||
|
<dimen name="sp_21">21sp</dimen>
|
||||||
|
<dimen name="sp_22">22sp</dimen>
|
||||||
|
<dimen name="sp_23">23sp</dimen>
|
||||||
|
<dimen name="sp_24">24sp</dimen>
|
||||||
|
<dimen name="sp_25">25sp</dimen>
|
||||||
|
<dimen name="sp_28">28sp</dimen>
|
||||||
|
<dimen name="sp_30">30sp</dimen>
|
||||||
|
<dimen name="sp_32">32sp</dimen>
|
||||||
|
<dimen name="sp_34">34sp</dimen>
|
||||||
|
<dimen name="sp_36">36sp</dimen>
|
||||||
|
<dimen name="sp_38">38sp</dimen>
|
||||||
|
<dimen name="sp_40">40sp</dimen>
|
||||||
|
<dimen name="sp_42">42sp</dimen>
|
||||||
|
<dimen name="sp_48">48sp</dimen>
|
||||||
|
|
||||||
|
</resources>
|
12
settings.gradle
Normal file
12
settings.gradle
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
include ':app'
|
||||||
|
include ':core'
|
||||||
|
include ':library'
|
||||||
|
include ':nim_uikit'
|
||||||
|
include ':easyphotos'
|
||||||
|
if (file("./modules/module_google/build.gradle").exists()) {
|
||||||
|
include ':modules:module_google'
|
||||||
|
}
|
||||||
|
include ':modules:module_base'
|
||||||
|
include ':libs:lib_core'
|
||||||
|
include ':libs:lib_utils'
|
||||||
|
include ':libs:lib_encipher'
|
108
方案.txt
Normal file
108
方案.txt
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# 项目重构技术方案
|
||||||
|
|
||||||
|
## 一、目标
|
||||||
|
- **语言迁移**:将原有 Java 代码逐步迁移到 Kotlin。
|
||||||
|
- **架构升级**:采用 MVVM(Model-View-ViewModel)架构,提高可维护性和可测试性。
|
||||||
|
- **现代化异步处理**:使用 Kotlin 协程和 Flow 替代 RxJava,简化异步编程模型。
|
||||||
|
- **事件总线更换**:使用 LiveDataBus , 替换现EventBus , LiveDataBus具备生命周期管理,不再需要单独注册回收,可跨进程通讯,可发粘性事件
|
||||||
|
- **RecyclerView Adapter 优化**: 引入 DiffUtil, 提升全局刷新的效率,避免不必要的消耗
|
||||||
|
- **更换屏幕适配方案**: 使用头条的适配方案 AndroidAutoSize 替换现屏幕适配方案
|
||||||
|
- **模块化设计**:按功能模块划分代码结构,增强模块解耦和复用能力。
|
||||||
|
- **模块路由TheRouter**:货拉拉提供的模块路由方案,替换掉已经不再更新维护的ARouter
|
||||||
|
- **Glide**:升级版本,尝试兼容 GZip ,提升图片加载效率
|
||||||
|
- **混淆方案**:ProGuard + aabResGuard + xmlClassGuard+包名隔离
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、技术选型
|
||||||
|
|
||||||
|
### 1. 编程语言
|
||||||
|
- **Kotlin**:全面使用 Kotlin 替代 Java,利用其简洁语法、空安全等特性。
|
||||||
|
|
||||||
|
### 2. 架构模式
|
||||||
|
- **MVVM(Model-View-ViewModel)**
|
||||||
|
- **Model**:数据层,包含网络请求、本地存储、业务逻辑等。
|
||||||
|
- **View**:UI 层,由 Activity 和 Fragment 实现。
|
||||||
|
- **ViewModel**:连接 Model 和 View 的桥梁,持有 UI 数据并提供生命周期感知的数据绑定。
|
||||||
|
|
||||||
|
### 3. 异步处理
|
||||||
|
- **Kotlin Coroutines + Flow**:替代 RxJava,简化异步操作和响应式编程。
|
||||||
|
- **LiveData/StateFlow**:用于在 ViewModel 和 View 之间传递 UI 数据变化。
|
||||||
|
|
||||||
|
### 4. RecyclerView
|
||||||
|
- **融云Provider方案/BaseRecyclerViewAdapterHelper**:选一个替代 原有adapter
|
||||||
|
- **DiffUtil**:工具会自动计算,差异化对比后只刷新对应的item,大幅度提升效率
|
||||||
|
|
||||||
|
### 5. 网络请求
|
||||||
|
- **Retrofit + OkHttp**:保留现有 Retrofit 网络框架,结合 Kotlin 协程进行优化。
|
||||||
|
- **协程封装**:统一封装网络请求,简化调用方式。
|
||||||
|
|
||||||
|
### 6. 数据库与本地缓存
|
||||||
|
- **Room**:本地持久化数据使用 Room 数据库。
|
||||||
|
- **CacheManager**:统一的缓存策略封装。//考虑
|
||||||
|
|
||||||
|
### 7. 事件总线
|
||||||
|
- **LiveDataBus** :替代 EventBus/RxBus,实现跨组件跨进程通信,事件生命周期管理,粘性事件收发。
|
||||||
|
|
||||||
|
### 8. 混淆
|
||||||
|
- **ProGuard** :基础混淆,自定义规则在 proguard-rules.pro 中。
|
||||||
|
- **aabResGuard** :资源文件名混淆保护,白名单机制保留关键资源,支持多语言保护
|
||||||
|
- **xmlClassGuard** :布局文件类名混淆,目录结构混淆,生成映射文件
|
||||||
|
- **包名隔离** :测试包跟正式包采用不同 包名
|
||||||
|
|
||||||
|
### 9. 工具库
|
||||||
|
- **Glide**:图片加载。尝试兼容GZip,因 Glide还充当下载 svga,mp4,如果GZip不能兼容这两种情况,那就只好放弃
|
||||||
|
- **TheRouter**:货拉拉团队开源的路由框架,使用ktps效率,编译效率远高于ARouter
|
||||||
|
- **uCrop**:裁剪图片框架,打算集成源码进项目,好应对各种需求
|
||||||
|
- **LeakCanary**:侦测内存泄漏
|
||||||
|
- **AndroidAutoSize**:头条适配方案
|
||||||
|
- **XCrash**:拦截 java层崩溃,so层崩溃,ANR,OOM 等,输出日志到本地,方便开发调试
|
||||||
|
- **饺子播放器/ExoPlayer**:优先ExoPlayer,谷歌推荐,且不加入FFmpeg扩展的情况下1MB左右
|
||||||
|
....
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、预计模块划分
|
||||||
|
|
||||||
|
| 模块名 | 功能说明 |
|
||||||
|
|--------|----------|
|
||||||
|
| [core] | 基础库,如网络、数据库、全局工具类等 |
|
||||||
|
| [common] | 公共库 |
|
||||||
|
| `app` | app层 |
|
||||||
|
| `login` | 登录注册相关逻辑 |
|
||||||
|
| `home` | 首页相关逻辑 |
|
||||||
|
| `dynamic` | 社区模块 |
|
||||||
|
| `game` | 游戏模块 |
|
||||||
|
| `message` | 云信模块|
|
||||||
|
| `mine` | 用户模块 |
|
||||||
|
| `room` | 房间模块 |
|
||||||
|
| `pay` | 支付相关模块 |
|
||||||
|
| `google` | 谷歌代码模块 |
|
||||||
|
| `develop` | 开发模块,存放一些不上线的代码,正式包不引入该模块 |(非必要)
|
||||||
|
| `library` | 工具库模块 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、迁移计划
|
||||||
|
|
||||||
|
| 阶段 | 内容 |
|
||||||
|
|------|------|----------|
|
||||||
|
| Phase 0 | 必要库,第三方引入,gradle升级,混淆方案出包,等兼容测试(优先保障混淆插件能运行,其他可做取舍,不断试错找到最优解)
|
||||||
|
| Phase 1 | 基础设施搭建,Kotlin 支持,协程封装,模块划分,启动页搭建,路由搭建...
|
||||||
|
| Phase 2 | 用户登录注册、社区模块,用户模块
|
||||||
|
| Phase 3 | 云信模块
|
||||||
|
| Phase 4 | 游戏模块
|
||||||
|
| Phase 5 | 房间模块
|
||||||
|
| Phase 6 | 支付模块
|
||||||
|
| Phase 7 | 后续工作...
|
||||||
|
....
|
||||||
|
---
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **保持兼容性**:新旧代码共存期间需做好桥接,避免破坏已有流程。
|
||||||
|
2. **代码质量保障**:
|
||||||
|
3. **文档同步更新**:重构过程中同步更新文档。
|
||||||
|
|
||||||
|
---
|
Reference in New Issue
Block a user