Creando una librería compartida para iOS de forma sencilla

La reutilización de código es algo que los desarrolladores buscamos continuamente. Con ella, conseguimos incrementar la calidad del producto, ya que volvemos a usar un código que ya ha sido empleado anteriormente y en el que tenemos total confianza. Al estar centralizada toda esta lógica, es más fácil mantenerla, tanto para aplicar posibles correcciones como para realizar modificaciones en la funcionalidad. El ámbito en el que podemos aplicar la reutilización no se restringe al propio proyecto. Podemos compartir código entre diferentes proyectos. De esta forma, podemos crear un código común y usarlo por ejemplo dos proyectos que estemos realizando en paralelo. O ir más allá y crear una librería con un conjunto de funcionalidades comunes que creemos que tendrán utilidad en futuros proyectos y usarla en todos ellos. Esto reducirá los costes de desarrollo de los futuros proyectos que las empleen. Esta entrada se centra justo en cómo compartir código entre diferentes proyectos, en este caso para proyectos iOS, aunque la idea se puede aplicar a otros lenguajes o tecnologías.

Como en muchos otros casos, no existe una única forma de crear esta reutilización de código entre proyectos. Por ejemplo, una idea sencilla, aunque posiblemente no sea la mejor, sería aprovechar que en los proyectos solemos usar como control de versiones Git. En cada uno de nuestros proyectos podríamos incorporar el código de la librería compartida como un submódulo Git. Es decir, el código compartido se escribiría en un repositorio Git separado y cada uno de los repositorios que lo necesitaran incluirían una referencia a él. Esta técnica es muy efectiva y sencilla de aplicar. Sin embargo, presenta el problema que la referencia al código compartido se hace estableciendo un puntero a un commit en concreto del repositorio del código compartido. Esta referencia no se actualizará salvo que se haga de forma manual. Es decir, si actualizamos la librería compartida tendremos que ir a cada uno de los proyectos a actualizar la referencia. Además, resulta complicado a simple vista saber qué versión de nuestra librería estamos usando, ya que la referencia se realiza apuntando a commits de Git y no a versiones numéricas del software. 

Para buscar una mejor alternativa hay que entender que este código compartido entre ambos proyectos en realidad es una dependencia de dichos proyectos. Es decir, podemos verlo como un código externo que necesitamos. De este modo, podemos introducir la librería compartida a través de Cocoa Pods, que es justo un gestor de dependencias para iOS. Estamos acostumbrados a usar Cocoa Pods para agregar librerías de terceros mediante la definición de las dependencias en el fichero Podfile. Por ejempo, es típico incluir la librería Alamofire para realizar peticiones HTTP incluyendo la siguiente línea en dicho fichero.

pod 'Alamofire', '~> 4.7'

Como vemos la referencia es a una versión en concreto, en este caso la release 4.7, y no un commit en concreto como anteriormente . Por lo tanto es mucho más sencillo saber en qué versión nos encontramos, acceder a la documentación de dicha versión y actualizarla si lo necesitásemos.

En ese ejemplo, estamos añadiendo una librería pública. Cocoa Pods también permite añadir librerías privadas. Para ello simplemente habría que publicar el pod en un repositorio que sólo estuviera accesible a las personas que lo necesiten. Por simplicidad, para evitar toda esta configuración operacional, vamos a optar por una alternativa en la que obtendremos resultados similares y podamos restringir su privacidad. Lo que haremos será crear una librería y cargarla como dependencia en los otros proyectos indicando la ruta relativa hasta donde se encuentra. De esta manera, será nuestro sistema de control de versiones el que determine la visibilidad de la librería. Si bien, tendremos que descargar la dependencia justo en la ruta en la que la esperamos. De este modo, aunque no estamos enlazando con una versión de la librería podemos asegurar que enlazaremos con el código que hay disponible en esa ruta. Podemos incluso emplear herramientas de integración continua o scripts para automatizar la descarga de la librería compartida a la versión que necesitamos. Por ejemplo, al último código disponible en la rama estable o a un tag de release de la librería compartida. Así, esto podría estar incluido como una etapa en la distribución de la aplicación con Bitrise.

Creando la librería paso a paso.

Lo primero que debemos hacer es instalar Cocoa Pods si es que no lo hemos hecho ya. La forma más sencilla de hacerlo es mediante la gema disponible de Ruby.

sudo gem install cocoapods

Una vez se haya instalado dispondremos del comando «pod» en el terminal. Podemos crear un proyecto llamado por ejemplo «shared_lib» mediante la siguiente llamada:

pod lib create shared_lib

Esto lanzará el proceso de creación de la librería. Se nos hará unas preguntas acerca de las características del pod a crear, como por ejemplo la plataforma en la que lo queremos emplear (iOS o macOS) o el tipo de lenguaje que queremos usar (Objective-C o Swift). Una vez se ha respondido a todas las preguntas se abrirá el proyecto en Xcode. Al haber empleado la llamada anterior para crear la librería, habremos empleado la plantilla por defecto. Esto significa que el proyecto tendrá una estructura muy particular. En la documentación Cocoa Pods se explica con detalle esta estructura. Para este ejemplo simplemente iremos a Pods/Development Pods/shared_lib y veremos que hay una clase llamada ReplaceMe.Swift. Podemos crear una clase nueva llamada MyLibrary.swift en esa misma localización y borrar ReplaceMe.Swift. Ten en cuenta que la estructura lógica dentro del proyecto no es la misma que la de los directorios y esa clase está fisicamente localizada en la carpeta  shared_lib/Classes. Dentro del fichero podemos crear una clase tan simple como esta para probar.

public class MyLibrary {

    public init() {
    }

    public func sayHi() {
        print("Hi from the shared library!");
    }

}

Ahora, vamos a intentar realizar una llamada a esa función de esa clase desde otro proyecto. Para ello crearemos un proyecto nuevo desde el que realizar la prueba de la llamada. La creación del proyecto será como siempre desde Xcode (File / New Project) y lo crearemos a la misma altura que el de la librería compartida. Es decir, que si este proyecto se llama MyProject, las carpetas «MyProject» y «shared_lib» se encuentran dentro de la misma carpeta, quedando una estructura de carpetas similar a esta.

+ MyProject

    - MyProject

    - MyProject.xcodeproj

    - MyProjectTests

+ shared_lib

Desde el terminal accederemos a la carpeta del proyecto (MyProject), es decir nos encontraremos en la carpeta donde se encuentra MyProject.xcodeproj e iniciaremos la integración con Cocoa Pods en el proyecto:

pod init

Esto creará el fichero Podfile en el que podremos añadir las dependencias del proyecto. Deberemos abrirlo y editarlo para indicarle la dependencia hacia la librería compartida y el target del proyecto. Para el target simplemente podemos descomentar la línea en la que aparece

platform :ios, '9.0'

eso hará que iOS 9.0 sea el target del proyecto. Para la librería compartida tendremos que indicarle la ruta relativa hasta la carpeta donde se encuentra la librería compartida shared_lib:

# Pods for MyProject

pod 'shared_lib', :path => '../shared_lib'

Ahora lanzaremos pod install para instalar las dependencias. El proceso creará un MyProject.xcworkspace en el que al abrirlo podemos ver que está tanto el código de nuestro proyecto como las dependencias asociadas.

En este proyecto podremos usar la clase de la dependencia simplemente importando el pod y ya tendremos acceso a las clases y métodos públicos de la librería compartida. Por ejemplo, en el delegado de nuestro proyecto podemos hacer:

import shared_lib

...

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    // Override point for customization after application launch.

    MyLibrary().sayHi();

    return true;
}

Si repasamos lo que hemos hecho, cuando hemos añadido la dependencia por primera vez, hemos usado pod install. Es importante saber que en caso de que ya tengamos añadida la dependencia al proyecto y el código de la librería compartida cambie, debemos ejecutar pod update para traernos los últimos cambios del código.

Conclusiones

Hemos visto una manera bastante sencilla de compartir código entre diferentes proyectos de iOS.  La idea es simple y se basa en cargar la librería desde una ruta relativa al proyecto. Podemos empezar con esta idea e iterar en ella, publicándola en un repositorio público para compartirla con todo el mundo o configurar nuestro propio repositorio de librerías interno de nuestra organización. En cualquier caso, esta técnica no es única de iOS. Podría aplicarse por ejemplo a Android creando una librería y cargándola con Gradle o en un servidor Node cargándola mediante npm. De esta manera podremos reducir nuestros ciclos de desarrollo y a la vez que mejorar la calidad de nuestro código.

Deja un comentario

¿Necesitas una estimación?

Calcula ahora