我们如何绕过审核指南并在电话上启动服务器

哈Ha 我叫Anton Loginov,我是FINCH的iOS开发人员。

最近,我们面临着使用基于Web的界面进行赌博的问题。 在AppStore审查指南的下一次更新中库比蒂诺的同事再次收紧了规定。 更具体地说,如果将任何基于Web的界面归为真钱赌博,则Apple现在可以重定向该应用程序。

仅我们的应用程序就是90%赌博,其余10%用于广告这些游戏。 其中一些通过webView工作,因此我们需要以任何方式保护自己免受重定向。

可以做什么:

  1. 将这些游戏带到主应用程序之外。
    换句话说,只需推迟不可避免的事情即可。
  2. 使用可以轻松更新游戏的容器。
    听起来不错→我想打穿→我花了几天时间研究React和React Native→我意识到“滑雪不行”→听起来不太好。

    这是一个非常昂贵的解决方案,因为时间很短,因此必须从头开始重写游戏。 全部与内部路由有关-完全与urlPathComponents绑定
  3. 本地实现游戏。
    很长,很贵,然后又很长。 将来,将不得不不断为其提供支持,但是我们没有这种机会。
  4. 模拟服务器的行为,该行为将为本地说谎的站点提供游戏。
    听起来很疯狂,但这是我选择的选项。 这是快速的,因为需要对游戏的遗留物进行最小的修改。
    估计的缺点包括:由于位于本地的站点而增加了组件的大小,通过启动服务器增加了设备的负载。

我没有在Habré上找到任何文章来描述如何在手机上启动服务器。 决定此案非常罕见且有趣之后,我决定在哈布雷(Habré)上谈论此案。

准备工作


当我们勇敢的主唱试图将游戏大小减少16倍(80 Mb-> 5 Mb)并将内部路径更改为相对时,我决定选择GCDWebServer来选择该库。 这是一个轻量级的框架,您可以用它用几行代码来引发HTTP服务器。

选择库之后,需要进行大量的研究和了解服务器在幕后的工作方式,在什么时间点发生什么情况,如何配置服务器以免浪费系统资源。 我们的服务器学会了捕捉过渡,对其进行处理,并且我学会了与路障另一侧的服务器一起工作。

客制化


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) } } 

开始


实际上,我们规定了用于启动服务器并运行的参数:

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

代理人


图片

该模块内部与API通信,但为​​此使用了自己的baseURL。 在本例中,为localhost。 因此,有必要教会服务器确定应转到API的那些请求,并更改其baseURL。

 // MARK: -     ,        Safari 

基于上述,有必要为特定任务配置处理程序:

  • 放弃该站点。 (嗯,这里一切都很简单)
  • 从捆绑包中给一些静电。 (取消请求url,将baseUrl更改为bundleUrl,给出内容(js /媒体)
  • 获取最新数据。 (网址不正确,已更改baseUrl,已请求,已返回)
  • 发送新数据。 (而且我们没有处理POST请求,没有拧紧它们,没有配置它们,没有发送过它们)

让我们做吧:

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

结论


既有趣又紧张。 首先,我以前从未做过这样的事情。 其次,直到最近我们还不了解我们的想法将如何影响父应用程序。

我们花了大约32个小时来实施:8个用于优化站点大小,24个用于设计和编写此功能。

在写文章时,我得出的结论是,使用该技术的一种更流行的方法是开发本机,而无需等待后端准备就绪。

好吧,总结一下所选方法的优点:

  • 通过为其提供数据模型节省后端时间
  • 能够测试任何服务器行为
  • 要从Mock切换到真实的API,我们只需要关闭特定的处理程序

谢谢您的关注。 如果您有类似的经历,请在评论中告诉我们。

Source: https://habr.com/ru/post/zh-CN471874/


All Articles