iOS: Simple way to manage REST end points

后端 未结 4 1154
既然无缘
既然无缘 2021-01-24 07:28

Our REST based application can be used for testing on multiple internal environments each with a different REST end point. Is there a simple way to set up environment level co

相关标签:
4条回答
  • 2021-01-24 07:58

    This is my approach of doing things when we have multiple end points. I used to make a ConfigurationManager class something like this

    Swift 3.0 code

    import Foundation
    import UIKit
    
    let kEnvironmentsPlist:NSString? = "Environments"
    let kConfigurationKey:NSString? = "ActiveConfiguration"
    let kAPIEndpointKey:NSString? = "APIEndPoint"
    let kLoggingEnabledKey:NSString? = "LoggingEnabled"
    let kAnalyticsTrackingEnabled:NSString? = "AnalyticsTrackingEnabled"
    
    class ConfigurationManager:NSObject {
    
        var environment : NSDictionary?
    
        //Singleton Method
    
        static let sharedInstance: ConfigurationManager = {
            let instance = ConfigurationManager()
            // setup code
            return instance
        }()
    
        override init() {
            super.init()
            initialize()
        }
    
        // Private method
    
        func initialize ()   {
    
            var environments: NSDictionary?
            if let envsPlistPath = Bundle.main.path(forResource: "Environments", ofType: "plist") {
                environments = NSDictionary(contentsOfFile: envsPlistPath)
            }
            self.environment = environments!.object(forKey: currentConfiguration()) as? NSDictionary
            if self.environment == nil {
                assertionFailure(NSLocalizedString("Unable to load application configuration", comment: "Unable to load application configuration"))
            }
        }
    
        // CurrentConfiguration
    
        func currentConfiguration () -> String   {
            let configuration = Bundle.main.infoDictionary?[kConfigurationKey! as String] as? String
            return configuration!
        }
    
        // APIEndpoint
    
        func APIEndpoint () -> String  {
            let configuration = self.environment![kAPIEndpointKey!]
            return (configuration)! as! String
        }
    
        // isLoggingEnabled
    
        func isLoggingEnabled () -> Bool  {
    
            let configuration = self.environment![kLoggingEnabledKey!]
            return (configuration)! as! Bool
        }
    
        // isAnalyticsTrackingEnabled
    
        func isAnalyticsTrackingEnabled () -> String  {
    
            let configuration = self.environment![kAnalyticsTrackingEnabled!]
            return (configuration)! as! String
        }
    
        func applicationName()->String{
            let bundleDict = Bundle.main.infoDictionary! as NSDictionary
            return bundleDict.object(forKey: "CFBundleName") as! String
        }
    }
    

    In Project--> Info Add some new configurations as per your need.

    I have added Staging and QA as extra endpoints.Generally I use to make Staging as Release config and QA as Debug. So it will look like:

    Now go to Targets -> Build Settings and add a User Defined Setting

    Give the name of the user defined like ACTIVE_CONFIGURATION.

    Add a key named ActiveConfiguration in info.plist with a variable name as $(ACTIVE_CONFIGURATION) same as given in User Defined Settings with a $ in the beginning. We gave the name of key as ActiveConfiguration because we are using the same name in our ConfigurationManager.swift class for kConfigurationKey.

    let kConfigurationKey:NSString? = "ActiveConfiguration"
    

    You can define as per your naming convention.

    It will look like:

    Now in the ConfigurationManager class I am getting a path for Environments.plist file.

    I will just make a Environments.plist file like this:

    The actual description source of this file is

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Development</key>
        <dict>
            <key>APIEndPoint</key>
            <string>https://dev</string>
            <key>LoggingEnabled</key>
            <true/>
            <key>AnalyticsTrackingEnabled</key>
            <true/>
            <key>Flurry</key>
            <dict>
                <key>FlurryApplicationID</key>
                <string></string>
                <key>FlurryApplicationSecret</key>
                <string></string>
            </dict>
            <key>Facebook</key>
            <dict>
                <key>FacebookAppID</key>
                <string></string>
                <key>FacebookAppSecret</key>
                <string></string>
            </dict>
        </dict>
        <key>QA</key>
        <dict>
            <key>APIEndPoint</key>
            <string>https://qa</string>
            <key>LoggingEnabled</key>
            <true/>
            <key>AnalyticsTrackingEnabled</key>
            <true/>
            <key>Flurry</key>
            <dict>
                <key>FlurryApplicationID</key>
                <string></string>
                <key>FlurryApplicationSecret</key>
                <string></string>
            </dict>
            <key>Facebook</key>
            <dict>
                <key>FacebookAppID</key>
                <string></string>
                <key>FacebookAppSecret</key>
                <string></string>
            </dict>
        </dict>
        <key>Staging</key>
        <dict>
            <key>APIEndPoint</key>
            <string>https://staging</string>
            <key>LoggingEnabled</key>
            <false/>
            <key>AnalyticsTrackingEnabled</key>
            <true/>
            <key>Flurry</key>
            <dict>
                <key>FlurryApplicationID</key>
                <string></string>
                <key>FlurryApplicationSecret</key>
                <string></string>
            </dict>
            <key>Facebook</key>
            <dict>
                <key>FacebookAppID</key>
                <string>840474532726958</string>
                <key>FacebookAppSecret</key>
                <string></string>
            </dict>
        </dict>
        <key>Production</key>
        <dict>
            <key>APIEndPoint</key>
            <string>https://production</string>
            <key>LoggingEnabled</key>
            <true/>
            <key>AnalyticsTrackingEnabled</key>
            <true/>
            <key>Flurry</key>
            <dict>
                <key>FlurryApplicationID</key>
                <string></string>
                <key>FlurryApplicationSecret</key>
                <string></string>
            </dict>
            <key>Facebook</key>
            <dict>
                <key>FacebookAppID</key>
                <string></string>
                <key>FacebookAppSecret</key>
                <string></string>
            </dict>
        </dict>
    </dict>
    </plist>
    

    We are now good to go. Now you have to just call

    ConfigurationManager.sharedInstance.APIEndpoint()
    

    for your respective end points.

    Now you just have to change the schemes from Edit Schemes and you are done and change the Build Configuration in info.

    This not only manages API End Points but also other things like whether to enable analytics or tracking for the respective end point or different ids of Facebook for different end points.

    0 讨论(0)
  • 2021-01-24 08:04

    As Zac Kwan suggested, you can use different schemes to accomplish this, but you don't necessarily have to create a different configuration as well. Each scheme can specify unique environment variables. Then, access them from Swift:

    let prodURL = "http://api.com"
    let baseURL = ProcessInfo.processInfo.environment["BASE_URL"] ?? prodURL
    
    0 讨论(0)
  • 2021-01-24 08:04

    I ended up using https://github.com/theappbusiness/ConfigGenerator:

    A command line tool to auto-generate configuration file code, for use in Xcode projects. The configen tool is used to auto-generate configuration code from a property list. It is intended to create the kind of configuration needed for external URLs or API keys used by your app. Currently supports both Swift and Objective-C code generation.

    0 讨论(0)
  • 2021-01-24 08:09

    I found that creating different Scheme and Configuration for your project works best. My setup is as follow:

    I usually have 3 different scheme, MyApp-dev, MyApp-staging and MyApp.

    Each of the scheme i created User-Defined-Attribute to have different string appending to my Bundle Display Name. So it can concurrently appear on my iOS device as MyApp-d, MyApp-s and MyApp. Each also have its own Bundle ID Then I create custom flags for each of them.

    So in my Routes.swift files i have something like this at the top:

    #if PRODUCTION
        static let hostName = "http://production.com/api/v1/"
    #elseif STAGING
        static let hostName = "http://staging.com/api/v1/"
    #else
        static let hostName = "http://development.com/api/v1/"
    #endif
    

    There is quite a few ways in how to update different hostname. But ultimately creating different Scheme and Configuration is always the first step.

    Here is a few links that might help you get started:

    https://medium.com/@danielgalasko/change-your-api-endpoint-environment-using-xcode-configurations-in-swift-c1ad2722200e#.o6nhic3pf

    http://limlab.io/swift/2016/02/22/xcode-working-with-multiple-environments.html

    0 讨论(0)
提交回复
热议问题