开发连接到api服务器的iOS应用程序,如果本地服务器正在运行,我希望应用程序连接到http://localhost:3000的本地开发api服务器。否则,应用程序应连接到生产服务器,例如https://example.com。
如何检查本地api服务器是否正在运行?
这仅在iOS模拟器中是必需的,而不是在真实的应用程序中。
答案 0 :(得分:1)
如果您正在开发一个应用程序并且正在组织生产代码,那么您应该至少拥有两个不同的构建版本。理想情况下,您最多可以有3个,一个用于开发,一个用于分段,一个用于生产。
在您的XCode项目中,您可以配置多个构建目标,然后可以将这些目标与iTunes Connect中的不同应用相关联,这样您就可以始终确保您的更改以开发构建为目标。
您真的不希望您的生产应用程序检查您的开发服务器API,因为您不希望您的用户在您处理更新时遇到该服务器。
This is a good starting point要设置目标,您可以立即启动并运行。有了这些不同的目标,您就可以为每个构建配置一个新的info.plist,并且总是一个好主意,也可以有一个不同的应用程序图标,让您知道您正在测试或使用不同的目标。
然后,您可以为每个目标配置所需数量的配置文件,配置文件可能如下所示:
Config.plist(以xml格式)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "...">
<plist version="1.0">
<dict>
<key>ClientId</key>
<string>{SomeIdValue}</string>
<key>ClientSecret</key>
<string>{ClientSecret}</string>
<key>ServerUrl</key>
<string>{my.target.apiEndpoint}</string>
</dict>
</plist>
然后,您可以拥有一个为您的应用程序提供正确的API端点配置的提供程序,如下所示(使用config.plist进行生产,使用configDebub.plist进行调试):
struct ConfigProvider {
#if DEVELOPMENT
let name: String = "configDebug"
#else
let name: String = "config"
#endif
enum ConfigError: ErrorType {
case FileNotWritten
case FileDoesNotExist
}
var sourcePath:String? {
guard let path = NSBundle.mainBundle().pathForResource(name, ofType: "plist") else { return .None }
return path
}
var destPath:String? {
guard sourcePath != .None else { return .None }
let dir = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
return (dir as NSString).stringByAppendingPathComponent("\(name).plist")
}
init?() {
let fileManager = NSFileManager.defaultManager()
guard let source = sourcePath else { return nil }
guard let destination = destPath else { return nil }
guard fileManager.fileExistsAtPath(source) else { return nil }
if !fileManager.fileExistsAtPath(destination) {
do {
try fileManager.copyItemAtPath(source, toPath: destination)
} catch let error as NSError {
print("Unable to copy file. ERROR: \(error.localizedDescription)")
return nil
}
}
}
func getConfig() -> NSDictionary?{
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath(destPath!) {
guard let dict = NSDictionary(contentsOfFile: destPath!) else { return .None }
return dict
} else {
return .None
}
}
func getServerUrl() -> String {
if let c = getConfig()?["ServerUrl"] {
return c as! String
}
// Handle error
}
func getClientSecret() -> String {
if let c = getConfig()?["ClientSecret"] {
return c as! String
}
// Handle error
}
func getClientId() -> String {
if let c = getConfig()?["ClientId"] {
return c as! String
}
// Handle error
}
func getMutablePlistFile() -> NSMutableDictionary?{
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath(destPath!) {
guard let dict = NSMutableDictionary(contentsOfFile: destPath!) else { return .None }
return dict
} else {
return .None
}
}
}
然后您可以将详细信息配置为:
private static let config = ConfigProvider()!
private let clientId = config.getClientId()
private let clientSecret = config.getClientSecret()
private let serverUrl = config.getServerUrl()
希望这有帮助!
答案 1 :(得分:0)
假设,在启动过程中的某个时刻,visitEntryPointUrl()
被调用。
func visitEntryPointUrl() {
if Device.isSimulator {
visitLocalServerIfRunningAndProductionServerOtherwiese()
} else {
visit(self.productionEntryPointUrl)
}
}
// Device.swift
import Foundation
struct Device {
// https://stackoverflow.com/a/30284266/2066546
static var isSimulator: Bool {
return TARGET_OS_SIMULATOR != 0
}
}
我从https://stackoverflow.com/a/30284266/2066546获取了这个技巧。
func visitLocalServerIfRunningAndProductionServerOtherwiese() {
let testSessionConfiguration =
NSURLSessionConfiguration.defaultSessionConfiguration()
testSessionConfiguration.timeoutIntervalForRequest =
NSTimeInterval(1) // seconds
testSessionConfiguration.timeoutIntervalForResource =
NSTimeInterval(1) // seconds
let testSession = NSURLSession(configuration: testSessionConfiguration)
let task = testSession.dataTaskWithURL(self.developmentEntryPointUrl) {
(data, response, error) -> Void in
// https://stackoverflow.com/a/28321213/2066546,
// https://stackoverflow.com/a/33715865/2066546
dispatch_async(dispatch_get_main_queue()) {
if data != nil {
print("local server running. connecting to \(self.developmentEntryPointUrl)")
self.visit(self.developmentEntryPointUrl)
} else {
print("server not running. connecting to \(self.productionEntryPointUrl)")
self.visit(self.productionEntryPointUrl)
}
}
}
task.resume()
}