Directorio de artículos
I. Introducción
Al usar RN para desarrollar una aplicación multiplataforma, al extraer el proyecto de git y usar Jenkins para empaquetar, se encuentra que el número de versión del paquete de instalación de ipa generado final siempre es inconsistente con el número de versión establecido en el proyecto.
2. Descripción del problema
Después de una cuidadosa investigación, se encontró que Jenkins Archive
falló en las etapas de compilación y archivado, pero Export
el paquete ipa se generó en las etapas posteriores.
error: Multiple commands produce '/Users/xxx/Library/Developer/Xcode/DerivedData/xxx-eomylkmdzkgaughihoblturddotc/Build/Products/Debug-iphonesimulator/PopNews.app':
1) Target 'xxx' has create directory command with output '/Users/xxx/Library/Developer/Xcode/DerivedData/xxx-eomylkmdzkgaughihoblturddotc/Build/Products/Debug-iphonesimulator/PopNews.app'
2) That command depends on command in Target 'xxx': script phase “[CP] Copy Pods Resources”
3. Resolución de problemas
Seleccione el objetivo del proyecto -> Fase de compilación -> Copiar recursos de pods -> Archivos de salida -> Eliminar${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH} -*
4. Lectura extendida
android
La configuración de la versión en android/app/build.gradle
el archivo es la siguiente:
android {
compileSdkVersion rootProject.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId "com.china.shq5785"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 18072801
versionName "2.2.5"
multiDexEnabled true
testBuildType System.getProperty('testBuildType', 'debug')
// This will later be used to control the test apk build type
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
ndk {
//设置支持的SO库架构
abiFilters "armeabi", "armeabi-v7a", "x86_64" //, "arm64-v8a"
}
missingDimensionStrategy 'react-native-camera', 'general'
}
......
}
ios
En el archivo de configuración ios/mrcs.xcodeproj/project.pbxproj
, puede ver la siguiente información de configuración:
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = AA6AA411A14368FB4EEC0CD3 /* Pods-mrcs.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = U4ALRF5A38;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/shq5785",
"$(PROJECT_DIR)",
);
GCC_PREFIX_HEADER = shq5785/PrefixHeader.pch;
GCC_WARN_ABOUT_RETURN_TYPE = NO;
HEADER_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = shq5785/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/shq5785",
);
MARKETING_VERSION = 2.2.5;
OTHER_CODE_SIGN_FLAGS = "--deep";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = com.china.shq5785;
PRODUCT_NAME = shq5785;
PROVISIONING_PROFILE_SPECIFIER = "1111";
SWIFT_OBJC_BRIDGING_HEADER = "$(PRODUCT_MODULE_NAME)/shq5785-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
5. Lectura extendida
El último paso del desarrollo de iOS es empaquetar y distribuir la aplicación, que se divide en dos pasos:
-
Archive
:Target
Compilar , archivar y generar.xcarchive
un archivo. -
Export
: Procese aún más los archivos de almacenamiento para generar paquetes.xcarchive
en diferentes canales para su distribución ..ipa
Cuando seleccionamos en el menú de Xcode , el sistema de compilación analizará, compilará y empaquetaráProduct -> Archive
el proyecto actual de Xcode , y finalmente generará un Archive ( archivo ) del Target de destino . Podemos ver toda la información del archivo histórico en caché en la página:Window -> Organizer -> Archives
El llamado " archivo " significa que después de compilar el código fuente, los diversos archivos, recursos y registros generados por esta compilación se unifican y encapsulan en un solo lugar, lo cual es conveniente para la administración y el seguimiento.
.xcarchive
Haga clic con el botón derecho en un archivo comprimido y luego haga clic en Mostrar en Finder, puede ver que se representa como un archivo con un sufijo en Finder .
Este .xcarchive
archivo contiene la aplicación y su información de tabla de símbolos ( symbol information
) y otros recursos relacionados. Haga clic con el botón derecho y seleccione Mostrar contenido del paquete para ver la estructura de archivo específica en un archivo de archivo:
El significado de cada carpeta:
-
BCSymbolMaps
La tabla de comparación generada por Xcode despuésBitCode
de ofuscar ( ) la tabla de símbolos , y el archivo tendrá una correspondencia uno a uno.Symbol Hiding
dSYM
-
dSYMs
almacena la tabla de símbolos compilada (debug symbols
), que se utiliza para resolver simbólicamente la pila de fallas. -
Productos
almacena el paquete de la aplicación ( ) generado por esta compilación.app
.
Cabe señalar que si bien este paquete incluye los archivos ejecutables y otros recursos que requiere la App para ejecutarse, será diferente a la versión descargada por el usuario final. Las operaciones posteriores export
lo procesarán aún más.
- SCMBlueprint Si la administración de versiones ( )
está habilitada en Xcode , la carpeta almacenará información de control de versiones para esta compilación, incluida la versión de git, el almacén, la sucursal, etc. utilizados.Preferences -> Source Control -> Enable Source Control
SCMBlueprint
Si desea volver a la versión fuente compilada en el futuro, puede SCMBlueprint
encontrar la información necesaria aquí.
- Si SwiftSupport se abre en
Target , el archivo de biblioteca estándar ( ) correspondiente a la versión de Swift utilizada en esta compilación se colocará en esta carpeta.Build Settings
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES
.dylib
Estas bibliotecas estándar también se copian en el paquete ipa cuando se lanza la aplicación.
Sin embargo, ahora que se ha estabilizado el ABI de Swift, el paquete escrito por Xcode 10.2 y versiones posteriores no necesita tener su propia biblioteca de enlaces en el paquete de aplicaciones de iOS 12.2 y sistemas posteriores, lo que ahorra cierto volumen.
Comprender el archivo ipa
El archivo ipa ( iOS App Store Package
) es el formato de la aplicación que finalmente se instala en el iPhone, incluyendo la firma, el paquete binario, los recursos, etc. necesarios para ejecutar la aplicación.
En Organizador, no importa qué método se utilice para aplicar el paquete de instalación, export
finalmente se genera un .ipa
archivo .
.ipa
Es un archivo de paquete comprimido. Si desea ver el contenido del ipa, puede hacer clic derecho para ver el contenido del paquete y observar el paquete descomprimido. Incluye principalmente los siguientes contenidos:
La información de la firma de la aplicación se colocará _CodeSignature
en la carpeta.
-
info.plist
El archivo plist que almacena la información principal de la aplicación también se empaquetará en ipa. -
derechos
derecho traducido literalmente al chino significa "derechos" y "autoridad".
Cuando Capabilities
habilita algunos permisos específicos en , Xcode generará automáticamente un .entitlements
archivo para usted y registrará estas autorizaciones en formato xml en este archivo.
Adelgazamiento de la aplicación
Para comprimir el tamaño del paquete de instalación de la aplicación, primero debe saber cuánto espacio ocupa el paquete de instalación y en qué partes consiste el espacio, y luego realizar una optimización específica.
Compruebe el tamaño del paquete de instalación del usuario final. De hecho , el paquete de la aplicación o el paquete ipa producido
localmente en Xcode será diferente de la versión descargada por el usuario final (por lo general, el volumen será mucho mayor). Debido a que Apple puede volver a compilar la aplicación (si se carga ), también distribuirá diferentes recursos (como imágenes 2x, 3x) para diferentes modelos de dispositivos y versiones de iOS, y finalmente comprimirá toda la aplicación para reducir la cantidad de archivos de la aplicación. La cantidad de tráfico consumido al descargar desde la Tienda.archive
export
BitCode
.ipa
Entonces, ¿cómo estimar el tamaño del paquete de la versión de descarga final del usuario? De hecho, se puede encontrar directamente en la página de iTunes Connect.
Abra iTunes Connect, seleccione Mis aplicaciones -> Actividad -> Todas las compilaciones y seleccione una compilación para ver:
Localice el botón de tamaño de archivo de App Store:
En la lista emergente, puede ver el tamaño del paquete descargado por diferentes dispositivos con la última versión del sistema iOS:
Dos columnas en la lista:
Tamaño de descarga: indica el tamaño de la aplicación comprimida descargada de forma inalámbrica;
Tamaño de la instalación: el espacio en disco que ocupará esta aplicación en el dispositivo del usuario después de la instalación;
¿Cómo analizar el tamaño del paquete de la aplicación?
Para ver qué recursos ocupan el volumen del paquete de instalación de la aplicación de forma más intuitiva, podemos usar algunas herramientas de archivos para analizar el paquete ipa descomprimido, como derlien
Puede ver intuitivamente la proporción de varios tipos de archivos.
Verifique los recursos no utilizados
Con la iteración continua de la aplicación, a menudo inadvertidamente introducimos muchos recursos que no se utilizan, o algunas referencias de recursos se han eliminado del código, pero no se han bundle
eliminado
Para encontrar estos recursos que ya no se utilizan, puede utilizar la herramienta de código abierto LSUnusedResources para detectar todo el proyecto.
El proceso de solicitud de LSUnusedResources es el siguiente:
Puede descargar el código fuente de LSUnusedResources desde la siguiente dirección
y luego compilarlo...Ejecute el código fuente en Mac, puede ver la siguiente interfaz: En el directorio Proyecto> Ruta, haga clic en Examinar... seleccione el directorio raíz del proyecto que se detectará y luego haga clic en Buscar para comenzar a buscar... Puede ver en la ventana de registro debajo de Resultado de la prueba>
Una vez completada la detección, puede hacer clic en Exportar para exportar el registro y luego comenzar el trabajo de limpieza. No abra ni elimine directamente independientemente de la causa, después de todo, es una detección de máquina y no se puede confiar por completo.
[UIImage imageNamed:[NSString stringWithFormat:@"icon_tag_%d", index]]
Para algunos casos especiales, como la referencia a recursos en el código mediante, por ejemplo, LSUnusedResources también admite el uso de expresiones regulares para la coincidencia aproximada.
Imágenes comprimidas Los
archivos de imágenes son los recursos más comunes en el paquete de instalación y, a menudo, ocupan una proporción considerable. Las imágenes sin comprimir suelen tener un tamaño bastante grande. Utilice algunas herramientas para comprimir recursos de imágenes y ahorrar espacio:
-
Compresión sin pérdidas: ImageOptim
-
Compresión con pérdida: tinypng
Uso de catálogos de activos para almacenar recursos
En comparación con arrastrar imágenes directamente al catálogo del proyecto, el uso de catálogos de activos ahorrará volumen. Los catálogos de activos utilizarán un formato especial altamente optimizado para almacenar todas las imágenes y también maximizarán la compresión de las imágenes png.
La plantilla del proyecto Xcode generará automáticamente un Assets.xcassets
archivo, y podemos crear otro según sea necesario .xcassets
Finalmente, en el paquete ipa, estos xcassets se comprimirán en Assets.car
el archivo, lo que también garantiza la seguridad hasta cierto punto.
Además de los recursos de imagen, los catálogos de activos también pueden almacenar texto, datos e incluso recursos relacionados con AR y Apple TV. Es muy versátil, por lo que una mejor práctica es:
Los recursos que pueden ser administrados por catálogos de activos deben ser administrados por catálogos de activos tanto como sea posible
Analice el archivo LinkMap
Como se mencionó anteriormente, una gran proporción del espacio ocupado por el paquete de la aplicación es el archivo ejecutable ( ) generado por la compilación final MACH-O
. El tamaño del archivo ejecutable no solo está relacionado con el tamaño del código, sino que también se ve afectado por la versión del compilador, las opciones de compilación, la biblioteca de enlaces, Influencias como la arquitectura de destino .
MACH-O
Puede comprender la composición del archivo analizando el LinkMap generado en el momento de la compilación .
Para encontrar el LinkMap correspondiente, primero Xcode Target -> Build Settings -> Write Link Map File
configúrelo en SÍ, y luego Target -> Build Settings -> Path to Link Map File
configure la dirección de generación de LinkMap en las opciones (generalmente use la dirección predeterminada en la carpeta de compilación). Después de que el archivo sea exitoso, podemos encontrar el LinkMap en la dirección correspondiente. El LinkMap compilado tiene:
LinkMap registra la información del enlace en tiempo de compilación, que se utiliza para describir los componentes estructurales del archivo ejecutable, incluida la distribución de segmentos de código __TEXT
y segmentos de datos :__DATA
Hay muchos scripts en Internet que pueden analizar y contar LinkMap, como:
herramienta de visualización
-
secuencia de comandos js
-
herramienta de línea de comandos
Después de obtener los resultados del análisis, puede comprender con precisión la ubicación y el espacio ocupado por cada módulo, biblioteca de enlaces y método en el archivo ejecutable:
Para algunos módulos con una proporción particularmente grande, las ideas de optimización comunes son:
Encuentre una biblioteca alternativa de dependencias de pequeño volumen o impleméntela usted mismo
Elimine conjuntos de instrucciones innecesarios en la biblioteca estática, como armv7s, x86, etc., y solo conserve los armv7 y arm64 necesarios para el lanzamiento.
Mejorar la reutilización de código
Analice más a fondo los métodos y módulos no utilizados en el código y simplifique la base del código.
El uso de código de bits
bitcode
es un lenguaje intermedio entre los lenguajes de front-end (OC, Swift, C) y los lenguajes de back-end (X86, código de máquina ARM) en el sistema LLVM .
Una compilación completa (desde el código fuente hasta .O
los archivos objeto) consta de tres pasos principales:
Front-end (
Frontend
): responsable de compilar varios tipos de códigos fuente enbitcode
representaciones de código intermedio.Optimización (
Optimizer
): responsable debitcode
realizar varios tipos de optimización ybitcode
realizar algunas conversiones lógicamente equivalentes en el código para hacerlo más eficiente y de menor tamaño.Backend (
Backend
): también conocido comoCodeGenerator
, es responsable de compilar elbitcode
código de máquina optimizado de la arquitectura de destino especificada, como x86, arm64, etc.
Puede activar la opción de código de bits en Xcode Target -> Configuración de compilación -> Habilitar código de bits , de modo que al archivar, el intermedio generado se incrustará bitcode
en el archivo binario vinculado ( .o
) para enviarlo a la App Store.
Como se mencionó anteriormente, bitcode
como lenguaje intermedio de LLVM, el programa final se puede compilar directamente desde él. Después de que Apple obtenga el código de bits que subimos, utilizará la última tecnología y compilador para recompilar la aplicación para diferentes dispositivos terminales, y estos recompilarán el La versión compilada tiende a ser más pequeña y más eficiente que la versión compilada nativa de Xcode.
Si existe la necesidad de admitir nuevas plataformas o tener nuevas innovaciones tecnológicas de compilación en el futuro, Apple no necesita depender de los desarrolladores para volver a cargar, y usa directamente lo listo para compilar una nueva versión bitcode
.
Vale la pena señalar que, al empaquetar, si algunas bibliotecas dependientes de terceros no están habilitadas bitcode
, o están habilitadas pero no incluidas en la biblioteca de enlaces de referencia final bitcode
, entonces no se puede usar todo el proyecto bitcode
para la compilación.
Recursos bajo demanda
Después de iOS9, Apple proporciona On-Demand Resources
la función para reducir el tamaño del paquete de instalación. Algunos recursos pueden marcarse como " carga bajo demanda " y solicitar al sistema operativo que los descargue de la App Store cuando sea necesario utilizarlos. Esta función es muy adecuada para algunos juegos grandes, aplicaciones con contenido pago o una gran cantidad de recursos multimedia de uso poco frecuente.
Por supuesto, la carga bajo demanda es solo para los archivos de recursos utilizados por la aplicación, sin incluir los archivos ejecutables binarios ni el código fuente.
La configuración de recursos bajo demanda se puede realizar fácilmente en Xcode.
Primero, cree una etiqueta de recurso en Destino -> Etiquetas de recursos. Una etiqueta representa un grupo de recursos que se pueden descargar de forma independiente. Luego, usaremos esta etiqueta para solicitar al sistema operativo que descargue el paquete de recursos correspondiente al local en el programa. .
Los recursos contenidos en diferentes etiquetas se pueden repetir, y la App Store diferirá por sí misma y no se descargará repetidamente.
Luego busque los archivos de recursos que desea cargar a pedido y asígneles una o más etiquetas creadas previamente.
Finalmente en el código, puedes usar NSBundleResourceRequest
:
Solicitud de descarga
on-demand
de recursos;Marcar los recursos como usados (para que los recursos descargados se limpien, ahorrando espacio local);
Administre el proceso de descarga de recursos, configure la prioridad, realice un seguimiento del progreso de la descarga, etc.;
Detectar advertencia de capacidad de disco;
El siguiente código es una solicitud de descarga de recursos simple:
// 配置要下载的 tags
NSSet *tags = [NSSet setWithObjects: @"birds", @"bridge", @"city"];// 创建 NSBundleResourceRequest 对象
resourceRequest = [[NSBundleResourceRequest alloc] initWithTags:tags];// 请求资源,处理回调
[resourceRequest beginAccessingResourcesWithCompletionHandler: ^(NSError * __nullable error) {
if (error) {
// 处理错误self.resourcesLoaded = NO;return;}// 下载成功,可以直接使用这些资源了self.resourcesAvailable = YES;}
];
El siguiente diagrama resume on-demand
el ciclo de vida de un recurso:
Digresión: Apple ha cancelado el límite de 150M para las descargas de la red móvil, lo que significa que con el aumento de la capacidad de los teléfonos móviles y la popularidad de las redes móviles, las personas ya no son tan sensibles al tamaño de los paquetes de instalación de la aplicación. mejores prácticas, generalmente no en el Hay un gran problema con este.