Cómo pasamos por alto las pautas de revisión y lanzamos un servidor en el teléfono

Hola Habr Mi nombre es Anton Loginov, soy desarrollador de iOS en FINCH.

Recientemente, enfrentamos el problema de usar interfaces basadas en la web para juegos de azar. En la próxima actualización de las Directrices de revisión de AppStore, los colegas de Cupertino volvieron a ajustar las reglas. Más específicamente, ahora Apple puede redirigir la aplicación si alguna de las interfaces basadas en la web se clasificará como un juego de dinero real.

Nuestra aplicación por sí sola es 90% de juegos de azar, y el 10% restante se utiliza para publicitar estos juegos. Algunos de ellos funcionan a través de webView, por lo que necesitábamos protegernos de la redirección de cualquier manera.

Qué se puede hacer:

  1. Lleva estos juegos fuera de la aplicación principal.
    En otras palabras, simplemente posponga lo inevitable.
  2. Use un contenedor para juegos que se puedan actualizar sin problemas.
    Suena bien → trató de penetrar → mató varios días para estudiar Reaccionar y Reaccionar nativo → se dio cuenta de que "el esquí no funciona" → no suena tan bien.

    Esta es una solución muy costosa, porque había poco tiempo y los juegos tendrían que reescribirse desde cero. Se trata de enrutamiento interno: está completamente vinculado a urlPathComponents
  3. Darse cuenta del juego de forma nativa.
    Largo, caro y de nuevo largo. En el futuro, tendrían que ser apoyados de forma continua, pero no tuvimos tales oportunidades.
  4. Simule el comportamiento de un servidor que proporcionaría un sitio local con juegos.
    Suena loco, pero esta es la opción que he elegido. Esto es rápido, ya que se requieren modificaciones mínimas al legado de los juegos.
    Las desventajas estimadas incluyen: aumentar el tamaño del ensamblaje debido al sitio local, aumentar la carga en el dispositivo al iniciar el servidor.

No encontré ningún artículo sobre Habré que describiera cómo iniciar el servidor en el teléfono. Habiendo decidido que el caso es bastante raro e interesante, decidí hablar sobre esto aquí en Habré.

Preparación


Si bien nuestro valiente líder intentó reducir el tamaño de los juegos en 16 veces (80 Mb -> 5 Mb) y cambió las rutas internas a relativas, decidí elegir la biblioteca seleccionando GCDWebServer. Este es un marco ligero con el que puede generar un servidor HTTP en unas pocas líneas de código.

Después de elegir la biblioteca, pasaron largas horas estudiando y entendiendo cómo funciona el servidor, qué sucede en qué momento, cómo configurar el servidor para que no desperdicie recursos del sistema. Nuestro servidor aprendió a atrapar transiciones, procesarlas, y aprendí a trabajar con el servidor al otro lado de las barricadas.

Personalización


func initWebServer() { //  let webServer = GCDWebServer() //       , ,     GET/POST : webServer.addDefaultHandler( forMethod: HTTPMethod.get.rawValue, request: GCDWebServerDataRequest.self) { [weak self] request in return self?.handle(request: request) } } 

Inicio


En realidad, prescribimos los parámetros para iniciar nuestro servidor y ejecutar:

 do { try webServer.start(options: [GCDWebServerOption_BindToLocalhost: true, GCDWebServerOption_Port: 8080]) } catch { assertionFailure(error.localizedDescription) webServer.start(withPort: 8080, bonjourName: "PROJECT_NAME Web Server") } 

Proxies


imagen

El módulo se comunica internamente con la API, pero utiliza su propia baseURL para esto. En nuestro caso, localhost. Por lo tanto, era necesario enseñarle al servidor a determinar aquellas solicitudes que deberían ir a la API y cambiar su baseURL.

 // MARK: -     ,        Safari 

Basado en lo anterior, fue necesario configurar controladores para tareas específicas:

  • Regala el sitio. (Bueno, todo es simple aquí) ;
  • Dar un poco de estática del paquete. (Desmontó la url de solicitud, cambió baseUrl a bundleUrl, proporcionó el contenido (js / media) ;
  • Obtenga los últimos datos. (URL desmantelada, baseUrl cambiada, solicitada, devuelta) ;
  • Enviar nuevos datos. (Y no procesamos solicitudes POST, las atornillamos, las configuramos, las enviamos) ;

Hagámoslo:

 private func handle(request: GCDWebServerRequest) -> GCDWebServerResponse? { // 1)   if request.url.pathComponents.contains(Endpoint.game.rawValue) { guard let indexURL = bundle.url(forResource: "index", withExtension: "html") else { return sendError(.noHTML(nil)) } do { let data = try Data(contentsOf: indexURL) let htmlString = String(data: data, encoding: .utf8) ?? "" return GCDWebServerDataResponse(html: htmlString) } catch { return sendError(.noHTML(error)) } // 2)   (js etc) } else if request.url.pathComponents.contains(Endpoint.nstatic.rawValue) { guard let resoursePath = bundle.resourcePath else { return sendError(.noJS(nil)) } let relativePath = request.url.pathComponents.joined(separator: "/") let absolutePath = resoursePath + relativePath.dropFirst() let staticURL = URL(fileURLWithPath: absolutePath) do { let data = try Data(contentsOf: staticURL) return GCDWebServerDataResponse(data: data, contentType: ContentType.js.description) } catch { return sendError(.noJS(error)) } // 3)    API } else if request.url.pathComponents.contains(Endpoint.api.rawValue) { var proxyRequest = request //  url,  , ,     let output = URLSession.shared.synchronousDataTask(with: proxyRequest) //    ,      let response = GCDWebServerDataResponse(data: outputData, contentType: ContentType.url.description) //     return response } } 

Conclusión


Fue divertido y nervioso. En primer lugar, nunca había hecho algo así antes. En segundo lugar, hasta hace poco no entendíamos cómo afectarán nuestras ideas a la solicitud de los padres.

Nos llevó alrededor de 32 horas implementar: 8 para optimizar el tamaño del sitio, 24 para diseñar y escribir esta funcionalidad.

Mientras escribía un artículo, llegué a la conclusión de que una forma más popular de usar esta tecnología es desarrollar un nativo sin esperar que el back-end esté listo.

Bueno, para resumir las ventajas del enfoque elegido:

  • Ahorre tiempo de backend dándole un modelo de datos
  • Capacidad para probar cualquier comportamiento del servidor
  • Para cambiar de Mock a la API real, solo tenemos que desactivar los controladores específicos

Gracias por su atencion Si tuvo una experiencia similar, cuéntenos en los comentarios.

Source: https://habr.com/ru/post/471874/


All Articles