Computer >> Máy Tính >  >> Hệ thống >> Android

Cách tự động tải Android App Bundle lên Cửa hàng Play

Trong bài viết này, tôi sẽ giải thích cách tự động tải Android App Bundle (tệp .aab) lên phiên bản beta của Cửa hàng Play. Chúng tôi sẽ sử dụng Android Studio và AWS làm nhà cung cấp cơ sở hạ tầng đám mây.

Khi chúng tôi đã tải lên gói ứng dụng, chúng tôi sẽ kích hoạt thông báo Slack.

Đây là cách sử dụng thời gian có giá trị của bạn vì một số lý do, chẳng hạn như tạo khả năng quan sát và ưu tiên các quy trình.

Công nghệ chúng tôi sẽ sử dụng

Dưới đây là các tài nguyên chúng tôi sẽ sử dụng cho hướng dẫn này:

  1. Android Studio
  2. AWS CodeBuild
  3. AWS Lambda
  4. S3
  5. Chần chừ

Tổng quan Cấp cao của Dự án

Cách tự động tải Android App Bundle lên Cửa hàng Play

Hình ảnh trên cho bạn thấy tổng quan chung về cách chúng tôi sẽ cấu trúc toàn bộ.

Về cơ bản, cần có một Đường ống mã được thiết lập trên AWS cho kho lưu trữ Android của bạn. Đường ống mã này sẽ có Xây dựng mã là một trong các giai đoạn của nó.

Việc đẩy đến nhánh chính của kho ứng dụng Android của bạn sẽ kích hoạt Bản dựng mã. Dự án xây dựng mã sẽ ký ứng dụng Android từ dòng lệnh và tải cấu phần phần mềm lên nhóm S3.

Tải gói lên S3 sẽ kích hoạt một Lambda, Lambda sẽ tải xuống gói và tải lên Cửa hàng Play bằng API xuất bản của Google. Sau khi nhận được 200 phản hồi, Lambda sau đó sẽ kích hoạt thông báo Slack.

Cách lấy khóa tài khoản dịch vụ Google Play của bạn

Để có thể sử dụng API nhà xuất bản của Google Play, bạn cần có khóa Tài khoản dịch vụ của Google Play.

Tài khoản dịch vụ là tài khoản có thể thay mặt bạn hoạt động khi các máy chủ đang giao tiếp với nhau. Bạn có thể đọc thêm về cách Google sử dụng OAuth2.0 để giao tiếp giữa máy chủ với máy chủ tại đây.

Để xem cách tạo tài khoản dịch vụ và cấp cho tài khoản đó quyền truy cập vào API nhà xuất bản của Google Play, hãy xem tại đây.

Khi bạn đã tạo tài khoản dịch vụ của mình và cấp cho nó các quyền thích hợp, hãy đảm bảo tải xuống khóa tài khoản dịch vụ và giữ nó an toàn. Bạn sẽ sớm tải tệp này lên nhóm S3.

Cách ký Android Bundle

Điều chính cần tìm ra là cách ký Android App Bundle. Google có tài liệu khá phong phú về nó mà bạn có thể tìm thấy tại đây.

Tôi sẽ tóm tắt các liên kết bên dưới.

Tạo khóa riêng tư bằng keytool như thế này:

keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias

Bạn có thể gọi khóa của mình bất cứ thứ gì bạn muốn. Ở đây, tôi gọi nó là my-release-key.jks . Bạn cũng có thể chọn bất kỳ bí danh nào bạn muốn. Trong suốt hướng dẫn này, hãy đảm bảo sử dụng đúng tên và bí danh cho khóa của bạn.

Mở build.gradle trong app của bạn trong Android Studio và thêm khối mã sau vào đó:

android {
    ...
    defaultConfig { ... }
    signingConfigs {
        release {
            // You need to specify either an absolute path or include the
            // keystore file in the same directory as the build.gradle file.
            storeFile file("my-release-key.jks")
            storePassword "password"
            keyAlias "my-alias"
            keyPassword "password"
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
            ...
        }
    }
}

Nếu bạn đã thay đổi tên khóa phát hành của mình thành một cái gì đó khác với tên mặc định, hãy đảm bảo chỉ định tên mới. Điều tương tự cho bí danh.

Mật khẩu cửa hàng của bạn sẽ là bất kỳ mật khẩu nào bạn đã tạo khi lần đầu tiên tải ứng dụng của mình lên Cửa hàng Play.

Bây giờ, khi bạn chạy lệnh ./gradlew :app:bundleRelease từ dòng lệnh trong Android Studio, bạn sẽ nhận thấy rằng nó tạo Gói ứng dụng đã ký.

Cách kiểm tra thông tin ký

Mã cam kết với thông tin ký có sẵn dưới dạng văn bản thuần túy trong build.gradle tệp là một rủi ro bảo mật và có thể là một vectơ tấn công.

Google có tài liệu về vấn đề này mà bạn có thể tìm thấy tại đây.

Đầu tiên, hãy tạo một keystore.properties tệp trong thư mục gốc của thư mục dự án của bạn.

Nội dung của tệp phải như sau:

storePassword=myStorePassword
keyPassword=myKeyPassword
keyAlias=myKeyAlias
storeFile=myStoreFileLocation

Mật khẩu cửa hàng và mật khẩu khóa của bạn sẽ là mật khẩu bạn đã sử dụng khi tải gói ứng dụng của mình lên App Store lần đầu tiên.

keyAlias của bạn và storeFile sẽ là bí danh bạn đã chỉ định khi tạo khóa cá nhân và vị trí của khóa cá nhân bạn đã tạo tương ứng.

Bây giờ, chúng ta cần tải tệp này vào build.gradle . Điều này khiến tôi ngạc nhiên ban đầu, nhưng Gradle thực sự hoạt động như một DSL. Vì vậy, việc viết cấu hình bằng Gradle dễ dàng hơn.

//  Load properties from keystore.properties
def keystorePropertiesFile = rootProject.file("keystore.properties")

//  Creating a new Properties() object
def keystoreProperties = new Properties()

//  If keystorePropertiesFile exists, read from that, else set from build environment
if (keystorePropertiesFile.exists()) {
    //  Loading the keystoreProperties file
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
} else {
    //  Read all environment variables from the build environment
    keystoreProperties.setProperty("storeFile", "${System.getenv('STORE_FILE')}")
    keystoreProperties.setProperty("keyAlias", "${System.getenv('KEY_ALIAS')}")
    keystoreProperties.setProperty("keyPassword", "${System.getenv('KEY_PASSWORD')}")
    keystoreProperties.setProperty("storePassword", "${System.getenv('STORE_PASSWORD')}")
}

Bạn sẽ nhận thấy điều kiện if trong đó - đừng lo lắng về điều đó ngay bây giờ. Nó ở đó đặc biệt để giải thích cho Code Build sau này.

Khi bạn thực hiện việc này, hãy thay đổi signingConfigs của bạn phần trong build.gradle trông như thế này:

signingConfigs {
        release {
            storeFile file(keystoreProperties['storeFile'])
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storePassword keystoreProperties['storePassword']
        }
    }

Cách thiết lập đường ống mã AWS

Tôi sẽ không đi vào quá nhiều chi tiết về vấn đề này vì nó tương đối đơn giản.

Thiết lập Đường ống mã AWS với ba giai đoạn sau:

  1. Giai đoạn nguồn được kết nối với master của kho lưu trữ GitHub của bạn chi nhánh
  2. Giai đoạn xây dựng được kết nối với Tạo mã AWS
  3. Giai đoạn triển khai sẽ triển khai tới nhóm S3.

Bạn có thể tìm thêm tài liệu về cách thiết lập Đường ống mã tại đây.

Cách thiết lập AWS S3

Trước tiên, hãy đảm bảo rằng bạn đã thiết lập Đường ống mã với Xây dựng mã là một trong các giai đoạn. Tiếp theo, thiết lập hai nhóm S3:

  1. Một nhóm để lưu trữ khóa phát hành của bạn. Tôi đang gọi nhóm này là release-key.jks
  2. Một bộ chứa trong đó bạn sẽ lưu trữ khóa cá nhân của Tài khoản Dịch vụ Google Play của mình. (Bạn nên tải xuống khóa này trong khi tạo tài khoản dịch vụ của mình.)

Bạn sẽ cần cho phép truy cập vào các nhóm này từ vai trò dịch vụ Xây dựng mã của mình. Vai trò dịch vụ Xây dựng mã của bạn nên được tạo khi bạn thiết lập Đường ống mã của mình.

Đi tới bảng điều khiển IAM và tìm vai trò dịch vụ Code Build của bạn và lấy ARN.

Tiếp theo, sử dụng bảng điều khiển để truy cập tab Quyền cho nhóm release-key.jks và thêm chính sách sau vào đó:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::123456789:role/service-role/codebuild-service-role-dummy",
                ]
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::release-key-bucket/*"
        }
    ]
}

Chính sách này sẽ cho phép truy cập vào nhóm S3 từ máy mà dự án CodeBuild của bạn sẽ thực thi.

Bạn sẽ cần thay thế các ARN được đề cập ở trên bằng ARN cho tài khoản của mình. Đảm bảo chỉ định đúng ARN cho vai trò dịch vụ Tạo mã khi bạn cập nhật chính sách.

Bạn không cần phải thay đổi chính sách quyền cho nhóm thứ hai. Chúng tôi sẽ thêm các quyền liên quan vào vai trò AWS Lambda để cho phép nó truy cập vào nhóm.

Cách thiết lập AWS CodeBuild

Tiếp theo, tạo buildspec.yml tệp trong thư mục gốc dự án của bạn.

version: 0.2

phases:
  build:
    commands:
      - aws s3api get-object --bucket release-key.jks --key release-key.jks ./releaseKey.jks
      - cp ./releaseKey.jks ${CODEBUILD_SRC_DIR}/app/releaseKey.jks
      - export STORE_FILE=releaseKey.jks
      - export KEY_ALIAS=$keyAlias
      - export KEY_PASSWORD=$keyPassword
      - export STORE_PASSWORD=$storePassword
      - ./gradlew :app:bundleRelease

artifacts:
  files:
    - app/build/outputs/bundle/release/app-release.aab

Tệp này khá đơn giản. Nó tìm nạp khóa phát hành từ nhóm được chỉ định và lưu nó vào một tệp cục bộ trên máy chủ Code Build vào vị trí được chỉ định.

Tiếp theo, xuất tất cả các biến cần thiết cho build.gradle cấu hình để hoạt động chính xác. Cuối cùng, chạy lệnh phát hành của Gradle từ dòng lệnh.

Trước khi có thể chạy tập lệnh này trong Xây dựng mã, bạn cần thêm các biến vào môi trường Xây dựng mã. Để thực hiện việc này, trước tiên hãy truy cập bảng điều khiển AWS Code Build và chọn dự án xây dựng cho ứng dụng Android của bạn.

Tiếp theo, chọn Chỉnh sửa> Môi trường như trong ảnh chụp màn hình bên dưới:

Cách tự động tải Android App Bundle lên Cửa hàng Play

Trên màn hình bật lên sau khi bạn thực hiện việc này, hãy chọn menu thả xuống Cấu hình bổ sung. Ở đó, bạn sẽ thấy một tùy chọn để thêm các biến môi trường thông qua các cặp giá trị khóa.

Bây giờ khi Code Build chạy buildspec.yml , nó sẽ có thể xuất các biến được chỉ định.

Hiện tại mọi thứ vẫn ổn, khi đường dẫn của bạn chạy, Code Build sẽ có thể tải xuống khóa riêng tư để ký và tạo ứng dụng Android của bạn cũng như tải gói đã ký lên nhóm S3.

Cách thiết lập ứng dụng Slack

Khả năng quan sát là một dấu hiệu nổi bật của tự động hóa. Bạn muốn biết khi nào quá trình tự động hóa của mình chạy, thành công hay thất bại và nếu thất bại, nguyên nhân dẫn đến thất bại.

Cách AWS thường xử lý khả năng quan sát là thông qua CloudWatch. Nhưng tôi nghĩ rằng tích hợp Slack cũng phục vụ cho mục đích này.

Cách dễ nhất để tích hợp Slack vào quy trình tự động hóa của bạn là thiết lập ứng dụng Slack và gửi thông báo đến ứng dụng đó từ quy trình làm việc tự động hóa của bạn.

Để tìm hiểu cách thiết lập ứng dụng Slack, hãy xem tài liệu tại đây. Quá trình này cực kỳ dễ dàng và bạn sẽ có một ứng dụng được thiết lập và chạy trong vài phút.

Sau khi tạo ứng dụng, bạn sẽ nhận được URL WebHook mà bạn có thể sử dụng để gọi ứng dụng đăng lên kênh có liên quan. Theo dõi URL WebHook này vì chúng tôi sẽ sử dụng URL này với chức năng AWS Lambda.

Cách thiết lập AWS Lambda

Cho đến nay, chúng tôi đã ký, xây dựng và tải Android App Bundle lên nhóm S3. Tiếp theo, chúng tôi cần tìm cách tải gói lên phiên bản beta trên Cửa hàng Play.

Cách để thực hiện việc này là thiết lập AWS Lambda sẽ được kích hoạt khi gói được tải lên nhóm S3. Khi trình kích hoạt này xảy ra, Lambda sẽ chạy, tải xuống gói, lấy khóa tài khoản dịch vụ và tải gói lên phiên bản beta của Cửa hàng Play.

Khi bạn đã tạo Lambda và thêm trình kích hoạt để chạy nó khi tệp được tải lên nhóm, hãy xem mã bên dưới:

"""This Python3 script is used to upload a new .aab bundle to the play store. The execution of this Python script
    occurs through an AWS Lambda which is invoked when a new file is uploaded to the relevant S3 buckets"""

import json
import boto3
import os
from urllib import request, parse
from google.oauth2 import service_account
import googleapiclient.discovery

#   Defining the scope of the authorization request
SCOPES = ['https://www.googleapis.com/auth/androidpublisher']

#   Package name for app
package_name = 'com.app.name'

#   Define the slack webhook url
slack_webhook_url = os.environ['SLACK_WEBHOOK_URL']

def send_slack_message(message):
    data = json.dumps({ 'text': message })
    post_data = data.encode('utf-8')
    req = request.Request(slack_webhook_url, data=post_data, headers={ 'Content-Type': 'application/json' })
    request.urlopen(req)

#   This is the main handler function
def lambda_handler(event, context):
    #   Create a new client S3 client and download the correct file from the bucket
    s3 = boto3.client('s3')
    s3.download_file('service-account-bucket-key', 'service-account-bucket-key.json', '/tmp/service-account-key.json')
    SERVICE_ACCOUNT_FILE = '/tmp/service-account-key.json'

    #   Download the app-release.aab file that triggered the Lambda
    bucket_name = event['Records'][0]['s3']['bucket']['name']
    file_key = event['Records'][0]['s3']['object']['key']
    s3.download_file(bucket_name, file_key, '/tmp/app-release.aab')
    APP_BUNDLE = '/tmp/app-release.aab'

    print(f"A bundle uploaded to {bucket_name} has triggered the Lambda")

    #   Create a credentials object and create a service object using the credentials object
    credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES
    )
    service = googleapiclient.discovery.build('androidpublisher', 'v3', credentials=credentials, cache_discovery=False)
    
    #   Create an edit request using the service object and get the editId
    edit_request = service.edits().insert(body={}, packageName=package_name)
    result = edit_request.execute()
    edit_id = result['id']

    #   Create a request to upload the app bundle
    try:
        bundle_response = service.edits().bundles().upload(
            editId=edit_id,
            packageName=package_name,
            media_body=APP_BUNDLE,
            media_mime_type="application/octet-stream"
        ).execute()
    except Exception as err:
        message = f"There was an error while uploading a new version of {package_name}"
        send_slack_message(message)
        raise err

    print(f"Version code {bundle_response['versionCode']} has been uploaded")

    #   Create a track request to upload the bundle to the beta track
    track_response = service.edits().tracks().update(
        editId=edit_id,
        track='beta',
        packageName=package_name,
        body={u'releases': [{
            u'versionCodes': [str(bundle_response['versionCode'])],
            u'status': u'completed',
        }]}
    ).execute()

    print("The bundle has been committed to the beta track")

    #   Create a commit request to commit the edit to BETA track
    commit_request = service.edits().commit(
        editId=edit_id,
        packageName=package_name
    ).execute()

    print(f"Edit {commit_request['id']} has been committed")

    message = f"Version code {bundle_response['versionCode']} has been uploaded from the bucket {bucket_name}.\nEdit {commit_request['id']} has been committed"
    send_slack_message(message)
    
    return {
        'statusCode': 200,
        'body': json.dumps('Successfully executed the app bundle release to beta')
    }

Lambda ở trên sẽ sử dụng googleapiclient thư viện và mô-đun khám phá của nó để tạo URL cho API xuất bản của Google Play.

Tiếp theo, Lambda sẽ tải xuống khóa tài khoản dịch vụ từ nhóm bạn đã thiết lập trước đó. Bạn sẽ phải đảm bảo rằng bạn chỉ định đúng tên nhóm.

Tùy thuộc vào việc tải lên thành công hay không thành công, chúng tôi muốn thông báo Slack xuất hiện. Thêm URL Slack WebHook từ phần trước vào các biến môi trường cho Lambda. Hàm trên sử dụng os của Python để có quyền truy cập vào biến môi trường và đăng thông báo lên Slack.

Nếu Lambda của bạn không thành công, có thể là do Lambda của bạn không có quyền truy cập vào nhóm S3 nơi lưu trữ khóa cho tài khoản dịch vụ Google Play của bạn. Trong trường hợp đó, bạn sẽ thấy thông báo lỗi cho biết điều này.

Để khắc phục điều này, bạn chỉ cần thêm các quyền liên quan vào vai trò Lambda của mình.

Đây là chính sách bạn sẽ cần thêm:

{
    "Version": "2012-10-07",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObjectVersion",
                "s3:GetBucketVersioning",
                "s3:GetBucketAcl",
                "s3:GetObject",
                "s3:GetBucketTagging",
                "s3:GetBucketLocation",
                "s3:GetObjectVersionAcl"
            ],
            "Resource": [
                "arn:aws:s3:::arn:aws:s3:::your-bucket-name-with-service-account-key"
            ]
        }
    ]
}

Thay thế ARN cho nhóm bằng ARN có liên quan cho tài khoản của bạn và bạn sẽ sẵn sàng.

Kết luận

Vì vậy, bạn có nó. Nó chắc chắn không dễ dàng và có rất nhiều bộ phận chuyển động, nhưng đây là một công cụ tự động hóa sẽ giúp bạn tiết kiệm rất nhiều thời gian và công sức.

Nếu bạn là thành viên của nhóm thường xuyên phát hành các bản cập nhật ứng dụng mới, bạn không muốn bị cản trở bởi sự vắng mặt của một người có nhiệm vụ phát hành bản cập nhật.

Việc xây dựng kiểu tự động hóa này giúp quy trình làm việc CI / CD của bạn mượt mà và mạnh mẽ hơn rất nhiều.

Nếu bạn quan tâm đến những blog như thế này, bạn có thể đọc thêm tại https://redixhumayun.github.io hoặc theo dõi tôi trên Twitter.