Swift-app动态切换服务器域名,还能手动输入

861 阅读2分钟

背景: 应用开发总是会涉及到多个环境之间的切换,难道要打不同的域名包,还得给应用改个名字:开发包,测试包,正式包。 这样做,是否太浪费时间了,打包不需要时间吗?这种磨人的操作有没有一劳永逸的方法?

方法我倒是替你想到了,而且适用各种不同场景。如:

  1. 多环境之间的切换
  2. 有时候服务器需要他本地调试怎么办?手动输入不是问题
  3. 打包老是忘记关闭环境切换?那就只在debug模式才能切换,测试包你也是可以打debug包的。

配置域名也非常简单,只需要在 allHostArray 填上你需要切换的环境域名跟备注,在 mainHost 设置默认的域名

在你方便的地方触发下环境切换吧。对只需一句代码

DebugEnvManager.showDebugEnvView()

网络请求获取域名

DebugEnvManager.getHomeHost()

主代码:

class DebugEnvManager: NSObject {

    static let mainHost = "https://xxx.com/"

    /// 文件地址 视频,图片需要拼接的前缀 默认追加files/

//    static let fileHost =

    static let allHostArray = [

    ("外网",              mainHost),

    ("测试",              "https://xxx.test.com/"),

    ("你自己输入吧",       "如:http://192.168.1.102:8080/"),

                           ]


    @objc class func getHomeHost() -> String {

        #if DEBUG

        if let host = UserDefaults.standard.object(forKey: "debug_env") as? String {
            if host.contains("如:") {
                if let selfHost = DebugEnvView.getCustomInputHost() {
                    return selfHost
                }
                return host.substingInRange(2..<host.count) ?? ""
            }
            return host

        }else {
            return mainHost
        }
        #endif
        return mainHost

    }

    /// 获取自动去除端口的地址
    class func getHomeHostNotPort() -> String {

        var urlString = getHomeHost()
        guard let url = URL(string: urlString), let port = url.port  else {
            return urlString
        }
        urlString = urlString.replacingOccurrences(of: ":\(port)", with: "")
        return urlString

    }

    

    @objc static func getHomeHostShopApp() -> String {
        return String.init(format: "\(self.getHomeHost())shop/")
    }

    

    @objc static func getHomeHostPath(_ path: String?) -> String {

        guard var path = path else {
            return self.getHomeHost()
        }

        if path.first == "/" {
            path = path.substingInRange(1..<path.count) ?? ""
        }
        return String.init(format: "\(self.getHomeHost())\(path)")

    }

    

    /// 获取自动编码后的图片地址
    @objc static func getImageURLPath(_ path: String?) -> String {

        var urlString = autoHostImageURLPath(path)
        if (URLComponents(string: urlString) == nil) {
            urlString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? urlString
        }
        return urlString
    }

    

    /// 自动拼接有效图片地址

    private static func autoHostImageURLPath(_ path: String?) -> String {

        guard var urlString = path, !urlString.isEmpty else {
            return ""
        }
        if urlString.first == "/" {
            urlString = urlString.substingInRange(1..<urlString.count) ?? ""
        }
        if urlString.contains("http") {
            return urlString
        }else {
            // 测试环境的图片拼接
            var host = getHomeHost()
            if host.contains("easydoc.xyz/mock") {
                return String.init(format: "http://106.1.0.69:8080/\(urlString)")
            }
            // 自己输入的文件地址
            if host == DebugEnvView.getCustomInputHost() {
                if let fileHost = DebugEnvView.getCustomInputFileHost() {
                    return String.init(format: "\(fileHost)\(urlString)")
                }
            }
            if !host.contains("9002") { // 文件地址统一添加 files
                return String.init(format: "\(host)files/\(urlString)")
            }
            host = host.replacingOccurrences(of: "9002", with: "8080")
            return String.init(format: "\(host)\(urlString)")
        }
    }

    @objc class func showDebugEnvView() {

        let view = DebugEnvView()
        view.setup()
        view.show()
    }

    // 是否是生成环境

    class func isProduction() -> Bool {

        if mainHost == DebugEnvManager.getHomeHost() {
            return true
        }
        return false
    }
}
UI视图代码

class DebugEnvView: UIView {


    let kDebugWindowHeight = UIScreen.main.bounds.height
    let kDebugWindowWidth = UIScreen.main.bounds.width
    private var _tableView: UITableView!

    func show() {
        if UIApplication.shared.keyWindow?.subviews.contains(self) ?? false {
            self.dimiss()
        }
        UIApplication.shared.keyWindow?.endEditing(true)
        self.alpha = 0.0
        UIApplication.shared.keyWindow?.addSubview(self)
        UIView.animate(withDuration: 0.3) {
            self.alpha = 1.0
        }
    }

    @objc func dimiss() {

        self.alpha = 1.0
        UIView.animate(withDuration: 0.3, animations: {
            self.alpha = 0.0
        }) { (_) in
            self.removeFromSuperview()
        }
    }

    func setup() {

        self.backgroundColor = UIColor.black.withAlphaComponent(0.3)
        self.frame = UIScreen.main.bounds
        self.addTapGesture()
        let count = DebugEnvManager.allHostArray.count

        let tableView = UITableView.init(frame: CGRect(x: 0, y: kDebugWindowHeight-CGFloat(count)*CGFloat(44.0), width: kDebugWindowWidth, height: CGFloat(count)*CGFloat(44.0)), style: .plain)
        tableView.estimatedSectionHeaderHeight = 0;
        tableView.estimatedSectionFooterHeight = 0;
        tableView.delegate = self
        tableView.dataSource = self
        tableView.tableFooterView = UIView()
        tableView.estimatedRowHeight = 0;
        self.addSubview(tableView)
        _tableView = tableView
    }
}


extension DebugEnvView: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let count = DebugEnvManager.allHostArray.count
        return count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
        if cell == nil {
            cell = UITableViewCell.init(style: .default, reuseIdentifier: "cell")
        }
        let hostName = DebugEnvManager.allHostArray[indexPath.row]
        let homeHost = DebugEnvManager.getHomeHost()
        cell?.separatorInset = UIEdgeInsets.zero
        cell?.layoutMargins = UIEdgeInsets.zero
        cell?.textLabel?.text = hostName.0
        cell?.textLabel?.font = UIFont.systemFont(ofSize: 14)
        cell?.textLabel?.textColor = UIColor.gray
        cell?.textLabel?.textAlignment = .center

        if hostName.1 == homeHost {
            cell?.textLabel?.textColor = UIColor.red
        }
        // 自己输入的
        if let selfHost = DebugEnvView.getCustomInputHost() {
            if homeHost == selfHost && hostName.1.contains("如:") {
                cell?.textLabel?.textColor = UIColor.red
                var allString = selfHost
                if let host = DebugEnvView.getCustomInputFileHost() {
                    allString = "\(allString)$$\(host)"
                }
                cell?.textLabel?.text = "输入地址:\(allString)"
            }
        }
        return cell!
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        tableView.deselectRow(at: indexPath, animated: true)
        self.dimiss()
        if customInputHost(DebugEnvManager.allHostArray[indexPath.row]) {
            return;
        }
        UserDefaults.standard.set(DebugEnvManager.allHostArray[indexPath.row].1, forKey: "debug_env")
        UserDefaults.standard.synchronize()
    }

    // 可以自己输入域名
    func customInputHost(_ host: (name: String,ip: String)) -> Bool {
        if host.0.contains("你自己输入吧") {
            // 文件地址用$$拼接在后面
            let alert = UIAlertController.init(title: "输入请求地址,记得+http://$$文件地址", message: nil, preferredStyle: .alert)
            alert.addTextField(configurationHandler: { (textF) in
                textF.placeholder = host.1
                var allString = ""
                if let host = DebugEnvView.getCustomInputHost() {
                    allString = host
                }
                if let host = DebugEnvView.getCustomInputFileHost() {
                    allString = "\(allString)$$\(host)"
                }
                textF.text = allString
            })

            alert.addAction(UIAlertAction.init(title: "确认", style: .default, handler: { (_) in
                guard let text = alert.textFields?[0].text else {
                    EPHud.showInfo("不想输入算了")
                    return;
                }

                if text.contains("http://") || text.contains("https://") {
                    let urls = text.components(separatedBy: "$$")
                    UserDefaults.standard.set(host.1, forKey: "debug_env")
                    UserDefaults.standard.set(urls[0], forKey: "debug_env_self_input")
                    if urls.count > 1 { // 获取文件地址
                        UserDefaults.standard.set(urls[1], forKey: "debug_env_self_input_file")
                    }
                    UserDefaults.standard.synchronize()
                    self.dimiss()
                }else {
                    EPHud.showInfo("记得添加http://前缀")
                }
            }))
            EPCtrlManager.getTopVC()?.present(alert, animated: true, completion: nil)
            return true;
        }
        return false
    }

    // 获取自己输入的请求域名
    static func getCustomInputHost() -> String? {
        if let selfHost = UserDefaults.standard.object(forKey: "debug_env_self_input") as? String {
            // 末尾自动追加 "/"
            if selfHost.last == "/" {
                return selfHost
            }else {
                return "\(selfHost)/"
            }
        }
        return nil
    }

    // 获取自己输入的文件域名
    static func getCustomInputFileHost() -> String? {
        if let selfHost = UserDefaults.standard.object(forKey: "debug_env_self_input_file") as? String {
            // 末尾自动追加 "/"
            if selfHost.last == "/" {
                return selfHost
            }else {
                return "\(selfHost)/"
            }
        }
        return nil
    }

}



extension DebugEnvView: UIGestureRecognizerDelegate {

    func addTapGesture() {
        let tapGes = UITapGestureRecognizer.init(target: self, action: #selector(dimiss))
        tapGes.delegate = self
        self.addGestureRecognizer(tapGes)
    }

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {

        let point = touch.location(in: self)
        return !_tableView.frame.contains(point)
    }

}