ReactNative avanzado (treinta y cuatro): ipa Error de error de etapa de archivo: Múltiples comandos producen reparación de problemas y pensamiento

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 Archivefalló en las etapas de compilación y archivado, pero Exportel 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

androidLa configuración de la versión en android/app/build.gradleel 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'
    }
    ......
}

iosEn 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:

  1. Archive: TargetCompilar , archivar y generar .xcarchiveun archivo.

  2. Export: Procese aún más los archivos de almacenamiento para generar paquetes .xcarchiveen 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

inserte la descripción de la imagen aquí
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.

.xcarchiveHaga 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 .

inserte la descripción de la imagen aquí

Este .xcarchivearchivo 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:

inserte la descripción de la imagen aquí
El significado de cada carpeta:

  • BCSymbolMaps
    La tabla de comparación generada por Xcode después BitCodede ofuscar ( ) la tabla de símbolos , y el archivo tendrá una correspondencia uno a uno.Symbol HidingdSYM

  • 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 exportlo 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 ControlSCMBlueprint

Si desea volver a la versión fuente compilada en el futuro, puede SCMBlueprintencontrar 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 SettingsALWAYS_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, exportfinalmente se genera un .ipaarchivo .

.ipaEs 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:

inserte la descripción de la imagen aquí
La información de la firma de la aplicación se colocará _CodeSignatureen 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 Capabilitieshabilita algunos permisos específicos en , Xcode generará automáticamente un .entitlementsarchivo 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.archiveexportBitCode.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:

inserte la descripción de la imagen aquí
Localice el botón de tamaño de archivo de App Store:

inserte la descripción de la imagen aquí

En la lista emergente, puede ver el tamaño del paquete descargado por diferentes dispositivos con la última versión del sistema iOS:

inserte la descripción de la imagen aquí

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

inserte la descripción de la imagen aquí

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 bundleeliminado

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:

  1. Puede descargar el código fuente de LSUnusedResources desde la siguiente dirección
    y luego compilarlo...

  2. Ejecute el código fuente en Mac, puede ver la siguiente interfaz: inserte la descripción de la imagen aquí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>

  3. 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.xcassetsarchivo, y podemos crear otro según sea necesario .xcassetsFinalmente, en el paquete ipa, estos xcassets se comprimirán en Assets.carel archivo, lo que también garantiza la seguridad hasta cierto punto.

640?wx_fmt=png

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-OPuede 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 Fileconfigúrelo en SÍ, y luego Target -> Build Settings -> Path to Link Map Fileconfigure 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:

640?wx_fmt=png

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 __TEXTy segmentos de datos :__DATA

640?wx_fmt=png
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:

640?wx_fmt=png

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 .

640?wx_fmt=png

Una compilación completa (desde el código fuente hasta .Olos archivos objeto) consta de tres pasos principales:

  • Front-end ( Frontend): responsable de compilar varios tipos de códigos fuente en bitcoderepresentaciones de código intermedio.

  • Optimización ( Optimizer): responsable de bitcoderealizar varios tipos de optimización y bitcoderealizar algunas conversiones lógicamente equivalentes en el código para hacerlo más eficiente y de menor tamaño.

  • Backend ( Backend): también conocido como CodeGenerator, es responsable de compilar el bitcodecó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á bitcodeen el archivo binario vinculado ( .o) para enviarlo a la App Store.

Como se mencionó anteriormente, bitcodecomo 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 bitcodepara la compilación.

Recursos bajo demanda
Después de iOS9, Apple proporciona On-Demand Resourcesla 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.

inserte la descripción de la imagen aquí

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. .

640?wx_fmt=png

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.

640?wx_fmt=png

Finalmente en el código, puedes usar NSBundleResourceRequest:

  • Solicitud de descarga on-demandde 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-demandel ciclo de vida de un recurso:

640?wx_fmt=png

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.

Guess you like

Origin blog.csdn.net/sunhuaqiang1/article/details/132305716