以编程方式而不是硬编码方式引用 AWS S3 存储桶名称

Referencing AWS S3 bucket name programmatically instead of hardcoded

我正在使用 AWS Amplify 开发一个 iOS 应用程序。我已经通过 S3 添加存储来托管一些资产,并且正在尝试配置应用程序来下载它们。唯一的问题是我看到的每个示例都对存储桶名称和路径进行了硬编码,但是因为我有多个环境并且有时会创建新环境并且每个存储桶都附加了环境名称,所以我不想重写存储桶每次命名。

例如,如果我在我的测试环境中,存储桶名称可能是 assetsxxxxxx-test 但如果我切换到一个新环境,我可能会引用 assetsyyyyy-dev 比方说。

问题是 aswconfiguration.json 文件中引用了存储桶名称:

"S3TransferUtility": {
    "Default": {
        "Bucket": "assetsxxxxx-test",
        "Region": "us-east-2"
    }
}

所以我的问题是如何以编程方式引用该存储桶名称,以便在我切换环境时重写该字段时,我不必更改我的代码。

谢谢

我不清楚您使用什么来构建您的 Amplify 资源(cloudformation、terrraform、?console?等),然后创建您的 'aswconfiguration.json file'。但听起来你需要传入一个非常容易实现的动态变量。

如果您使用代码管道、代码构建安排来部署您的资源和配置文件,您可以在代码构建阶段使用 bash 命令(sed 或 perl)来更改变量。或者自定义 lambda 更新文件内容并复制到 S3,然后将动态变量传递到环境变量参数中。

通常情况下,如果这是一个 cloudformation 模板,您可以使用伪参数引用 !Sub command,然后该参数将在早期声明并引用它所在的任何环境,例如

"Bucket": "asssetsxxxxxx-${Environment}"

我解决了。对于其他想知道的人,我仍然不确定 AWS SDK 是否内置了一个字段,但我决定直接将 awsconfiguration.json 文件解析为自定义结构:

struct AWSConfigurationJSON: Codable{
    let S3TransferUtility: S3TransferUtility
}

struct S3TransferUtility: Codable{
    let Default: S3TransferUtilityDefault
}

struct S3TransferUtilityDefault: Codable{
    let Bucket: String
    let Region: String
}

然后我读取文件并解析 JSON.

if let path = Bundle.main.path(forResource: "awsconfiguration", ofType: "json") {
            do{
                let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
                let jsonResult = try JSONDecoder().decode(AWSConfigurationJSON.self, from: data)
                print(jsonResult.S3TransferUtility.Default.Bucket)
                bucketPath = jsonResult.S3TransferUtility.Default.Bucket
            }catch let e{
                print("error \(e)")
                bucketPath = ""

            }
        }else{
            bucketPath = ""

        }

我也有同样的问题。我的解决方案相似但不完全相同。 首先,我像这样创建了 Codable 结构

import Foundation

struct AwsConfiguration: Codable {
    struct S3TransferUtility : Codable {
        private enum CodingKeys: String, CodingKey {
            case defaultConfig = "Default"
        }

        struct DefaultConfig : Codable {
            private enum CodingKeys: String, CodingKey {
                case bucket = "Bucket"
                case region = "Region"
            }
            var bucket: String
            var region: String
        }

        var defaultConfig: DefaultConfig
    }

    private enum CodingKeys: String, CodingKey {
        case s3TransferUtility = "S3TransferUtility"
    }

    var s3TransferUtility: S3TransferUtility
}

然后我定义了一个 DataHelper class

final class DataHelper {
    static func load<T: Decodable>(_ filename: String, as type: T.Type = T.self) -> T {
        let data: Data

        guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
            else {
                fatalError("Couldn't find \(filename) in main bundle.")
        }

        do {
            data = try Data(contentsOf: file)
        } catch {
            fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
        }

        do {
            let decoder = JSONDecoder()
            return try decoder.decode(T.self, from: data)
        } catch {
            fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
        }
    }
}

然后将 awsconfiguration.json 放入您的测试目标中。 然后你可以像这样写一个单元测试

    func testReadAWSConfiguration() throws {
        let config: AwsConfiguration = DataHelper.load("awsconfiguration.json")

        print ("************config bucket: \(config.s3TransferUtility.defaultConfig.bucket) " +
            "\n************config region: \(config.s3TransferUtility.defaultConfig.region)")
        XCTAssertNotEqual("", config.s3TransferUtility.defaultConfig.bucket)
        XCTAssertNotEqual("", config.s3TransferUtility.defaultConfig.region)
    }

您可以使用以下方法访问存储桶名称:

if let s3TransferInfo = AWSInfo.default().defaultServiceInfo("S3TransferUtility") {
    self.bucket = s3TransferInfo.infoDictionary["Bucket"] as? String
}

所以您不需要自己JSON解析配置