এই আর্টিকেলে, আমি ব্যাখ্যা করব কিভাবে একটি অ্যান্ড্রয়েড অ্যাপ বান্ডেল (.aab ফাইল) প্লে স্টোরের বিটা ট্রকে স্বয়ংক্রিয়ভাবে আপলোড করব। আমরা অ্যান্ড্রয়েড স্টুডিও এবং AWS ক্লাউড ইনফ্রাস্ট্রাকচার ব্যবহার করব।
অ্যাপ বান্ডেল আপলোড হলে, আমরা একটি স্ল্যাক নোটিফিকেশন ট্রিগার করব।
এটি আপনার সময়ের একটি মূল্যবান ব্যবহার অনেক কারণে, যেমন অবজার্বেবিলিটি তৈরি করা এবং প্রসেসগুলোকে প্রায়োরিটি দেয়া।
ব্যবহার করা টেকনোলজি
এই টিউটোরিয়ালে আমরা যেসব রিসোর্স ব্যবহার করব:
- অ্যান্ড্রয়েড স্টুডিও
- AWS CodeBuild
- AWS Lambda
- S3
- Slack
প্রজেক্টের হাই লেভেল ওভারভিউ

উপরোক্ত ছবিটি আপনাকে দেখাবে আমরা পুরো জিনিসটি কিভাবে স্ট্রাকচার করব।
অসলে, আপনার অ্যান্ড্রয়েড রিপোজিটরির জন্য AWS-এ একটি কোড পাইপলাইন সেট আপ থাকতে হবে। এই কোড পাইপলাইনে Code Build একটি স্টেজ হিসেবে থাকবে।
আপনার অ্যান্ড্রয়েড অ্যাপ রিপোজিটরির master ব্রাঞ্চে পুশ করলে Code Build ট্রিগার হবে। Code Build প্রজেক্টটি কমান্ড লাইন থেকে অ্যান্ড্রয়েড অ্যাপ সাইন করবে এবং আর্টিফ্যাক্টকে একটি S3 বাকেটে আপলোড করবে।
বান্ডেলটি S3-এ আপলোড হলে একটি ল্যাম্বডা ট্রিগার হবে, যা বান্ডেলটি ডাউনলোড করে গুগল পাব্লিশিং API ব্যবহার করে প্লে স্টোরে আপলোড করবে। ২০০ রেসপন্স পাওয়ার পর, ল্যাম্বডা একটি স্ল্যাক নোটিফিকেশন ট্রিগার করবে।
গুগল প্লে সার্ভিস অ্যাকাউন্ট কী পাওয়ার পদ্ধতি
গুগল প্লে পাব্লিশার API ব্যবহার করতে, আপনার একটি গুগল প্লে সার্ভিস অ্যাকাউন্ট কী লাগবে।
এক সার্ভিস অ্যাকাউন্ট হল একটি অ্যাকাউন্ট যা সার্ভারগুলো একে অপরের সাথে কমিউনিকেট করলে আপনার পক্ষে কাজ করতে পারে। গুগল কিভাবে OAuth2.0 ব্যবহার করে সার্ভার-টু-সার্ভার কমিউনিকেশন করে সেটা এখানে পড়ুন।
সার্ভিস অ্যাকাউন্ট তৈরি করে এবং এটিকে গুগল প্লে পাব্লিশার API-এ অ্যাক্সেস দিয়ে কিভাবে করবেন সেটা এখানে দেখুন।
সার্ভিস অ্যাকাউন্ট তৈরি করে এবং উপযুক্ত পারমিশন দিয়ে থাকলে, সার্ভিস অ্যাকাউন্ট কী ডাউনলোড করে ভালোভাবে রাখুন। আপনি শীঘ্রই এটিকে একটি S3 বাকেটে আপলোড করবেন।
অ্যান্ড্রয়েড বান্ডেল সাইন করার পদ্ধতি
মূল বিষয় হলো অ্যান্ড্রয়েড অ্যাপ বান্ডেল কিভাবে সাইন করবেন। গুগলের এতে পর্যায়পর্যায় ডকুমেন্টেশন আছে যা এখানে পাবেন।
নিচে লিংকগুলো সংক্ষেপে দেওয়া হলো।
keytool ব্যবহার করে একটি প্রাইভেট কী জেনারেট করুন:
keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias
আপনি আপনার কীকে যেকোনো নাম দিতে পারেন। এখানে আমি my-release-key.jks নাম দিয়েছি। আপনি যেকোনো এলিয়াসও বেছে নিতে পারেন। এই টিউটোরিয়ালে সঠিক নাম এবং এলিয়াস ব্যবহার করতে ভুলবেন না।
অ্যান্ড্রয়েড স্টুডিওতে আপনার app ডিরেক্টরির ভিতরে build.gradle খুলুন এবং নিচের কোড ব্লক যোগ করুন:
android { ... defaultConfig { ... } signingConfigs { release { // আপনাকে অবсолют পাথ স্পেসিফাই করতে হবে অথবা কীস্টোর ফাইলটি build.gradle ফাইলের সেম ডিরেক্টরিতে রাখতে হবে। storeFile file("my-release-key.jks") storePassword "password" keyAlias "my-alias" keyPassword "password" } } buildTypes { release { signingConfig signingConfigs.release ... } } }
আপনি যদি আপনার রিলিজ কীর নাম ডিফল্ট থেকে অন্য কিছু করে থাকেন, তবে নতুন নাম স্পেসিফাই করুন। এলিয়াসের জন্যও একই কথা।
আপনার স্টোর পাসওয়ার্ড হবে যেটি আপনি প্রথমবার অ্যাপ প্লে স্টোরে আপলোড করার সময় জেনারেট করেছিলেন।
এখন, অ্যান্ড্রয়েড স্টুডিওতে কমান্ড লাইন থেকে ./gradlew :app:bundleRelease কমান্ড চালালে, আপনি দেখবেন এটি একটি সাইনড অ্যাপ বান্ডেল জেনারেট করে।
সাইনিং ইনফরমেশন স্ক্রাব করার পদ্ধতি
সাইনিং ইনফরমেশন প্লেইন টেক্সট হিসেবে build.gradle ফাইলে রেখে কোড কমিট করা একটি সিকিউরিটি রিস্ক এবং অ্যাট্যাক ভেক্টর হতে পারে।
গুগলের এতে ডকুমেন্টেশন আছে যা এখানে পাবেন।
প্রথমে, আপনার প্রজেক্ট ডিরেক্টরির রুটে একটি keystore.properties ফাইল তৈরি করুন।
ফাইলটির কন্টেন্ট নিচের মত হবে:
storePassword=myStorePassword keyPassword=myKeyPassword keyAlias=myKeyAlias storeFile=myStoreFileLocation
আপনার স্টোর পাসওয়ার্ড এবং কী পাসওয়ার্ড হবে সেটি যা আপনি প্রথমবার অ্যাপ বান্ডেল অ্যাপ স্টোরে আপলোড করার সময় ব্যবহার করেছিলেন।
আপনার keyAlias এবং storeFile হবে প্রাইভেট কী তৈরি করার সময় আপনি যে এলিয়াস দিয়েছিলেন এবং প্রাইভেট কীটির লোকেশন।
এখন, এই ফাইলটি build.gradle-এ লোড করতে হবে। এটা আমাকে প্রথমে বিস্মিত করল, কিন্তু Gradle আসলে একটি DSL হিসেবে কাজ করে। তাই কনফিগারেশন লিখতে Gradle ব্যবহার করা সহজ হয়।
// keystore.properties থেকে প্রপার্টি লোড করুন def keystorePropertiesFile = rootProject.file("keystore.properties") // নতুন Properties() অবজেক্ট তৈরি করুন def keystoreProperties = new Properties() // যদি keystorePropertiesFile এক্সিস্ট করে, সেটি থেকে পড়ুন, অন্যথায় বিল্ড এনভায়রনমেন্ট থেকে সেট করুন if (keystorePropertiesFile.exists()) { // keystoreProperties ফাইল লোড করুন keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) } else { // বিল্ড এনভায়রনমেন্ট থেকে সব এনভায়রনমেন্ট ভেরিয়েবল পড়ুন 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')}") }
আপনি if কন্ডিশনটি লক্ষ্য করলেন – এখনি চিন্তা করবেন না। এটি স্পেসিফিক্যালি Code Build-এর জন্য আছে।
এটি করলে, build.gradle-এ আপনার signingConfigs সেকশনকে নিচের মত করে পরিবর্তন করুন:
signingConfigs { release { storeFile file(keystoreProperties['storeFile']) keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storePassword keystoreProperties['storePassword'] } }
AWS Code Pipeline সেট আপ করার পদ্ধতি
এত বিস্তারিত এতে যাব না কারণ এটি 상대적으로 straightforward।
নিচের তিনটি স্টেজসহ একটি AWS Code Pipeline সেট আপ করুন:
- সোর্স স্টেজ আপনার GitHub রিপোজিটরির
masterব্রাঞ্চের সাথে কানেক্টেড - বিল্ড স্টেজ AWS Code Build-এর সাথে কানেক্টেড
- ডিপ্লয় স্টেজ যা একটি S3 বাকেটে ডিপ্লয় করবে।
Code Pipeline সেট আপ করার আরও ডকুমেন্টেশন এখানে পাবেন।
AWS S3 সেট আপ করার পদ্ধতি
প্রথমে, নিশ্চিত করুন আপনার কাছে Code Build এক স্টেজ হিসেবে থাকা একটি Code Pipeline সেট আপ আছে। তারপর, দুটি S3 বাকেট সেট আপ করুন:
- আপনার রিলিজ কী সংরক্ষণ করার জন্য একটি বাকেট। আমি এটিকে
release-key.jksনামে ডাকছি - একটি বাকেট যেখানে আপনার গুগল প্লে সার্ভিস অ্যাকাউন্ট প্রাইভেট কী সংরক্ষণ করবেন। (সার্ভিস অ্যাকাউন্ট তৈরি করার সময় আপনি এই কীটি ডাউনলোড করেছেন বলে আশা করি।)
আপনাকে আপনার Code Build সার্ভিস রোল থেকে এই বাকেটগুলোর অ্যাক্সেস দিতে হবে। আপনার Code Build সার্ভিস রোলটি আপনি Code Pipeline সেট আপ করার সময় তৈরি হয়েছিল বলে আশা করি।
IAM কনসোলে যান এবং আপনার Code Build সার্ভিস রোল খুঁজে বের করুন এবং ARN টি গ্র্যাব করুন।
পরবর্তীতে, কনসোল ব্যবহার করে release-key.jks বাকেটের Permissions ট্যাবে যান এবং নিচের পলিসি যোগ করুন:
{ "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/*" } ] }
এই পলিসিটি Code Build প্রজেক্ট এক্সিকিউট হবে সেই মেশিন থেকে S3 বাকেটে অ্যাক্সেস দেবে।
উপরে উল্লিখিত ARNগুলো আপনার অ্যাকাউন্টের ARN দিয়ে রিপ্লেস করুন। Code Build সার্ভিস রোলের সঠিক ARN স্পেসিফাই করতে ভুলবেন না পলিসি আপডেট করার সময়।
দ্বিতীয় বাকেটের পারমিশন পলিসি পরিবর্তন করার দরকার নেই। AWS Lambda রোলে প্রাসঙ্গিক পারমিশন যোগ করব যাতে সেটি বাকেটটি অ্যাক্সেস করতে পারে।
AWS CodeBuild সেট আপ করার পদ্ধতি
পরবর্তী, আপনার প্রজেক্ট রুট ফোল্ডারে একটি buildspec.yml ফাইল তৈরি করুন।
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
এই ফাইলটি সহজ। এটি নির্দিষ্ট বাকেট থেকে রিলিজ কী ফেচ করে এবং Code Build সার্ভারের লোকাল ফাইলে নির্দিষ্ট লোকেশনে সেভ করে।
এরপর, build.gradle কনফিগারেশন সঠিকভাবে কাজ করার জন্য প্রয়োজনীয় সব ভেরিয়েবল এক্সপোর্ট করুন। শেষে, কমান্ড লাইন থেকে Gradle-এর রিলিজ কমান্ড চালান।
এই স্ক্রিপ্ট Code Build-এ চালানোর আগে, আপনাকে ভেরিয়েবলগুলো Code Build এনভায়রনমেন্টে যোগ করতে হবে। সেটা করতে, প্রথমে AWS Code Build কনসোলে যান এবং আপনার অ্যান্ড্রয়েড অ্যাপের বিল্ড প্রজেক্ট বেছে নিন।
পরবর্তী, Edit > Environment সিলেক্ট করুন (নিচের স্ক্রিনশটের মত):

পপ আপ স্ক্রিনে, Additional Configuration ড্রপডাউন সিলেক্ট করুন। সেখানে এনভায়রনমেন্ট ভেরিয়েবল কী-ভ্যালু পেয়ার হিসেবে যোগ করার অপশন থাকবে।
এখন Code Build buildspec.yml ফাইলটি চালালে, সেটি স্পেসিফাইড ভেরিয়েবলগুলো এক্সপোর্ট করতে পারবে।
এই মুহূর্তে, আপনার পাইপলাইন রান করলে, Code Build আপনার অ্যান্ড্রয়েড অ্যাপ সাইন ও বিল্ড করতে এবং সাইনড বান্ডেলকে একটি S3 বাকেটে আপলোড করতে পারবে।
Slack অ্যাপ সেট আপ করার পদ্ধতি
অবজার্বেবিলিটি অটোমেশনের একটি হ্যালমার্ক। আপনি জানতে চান আপনার অটোমেশন কখন চলে, সফল হয় বা ফেল, এবং ফেল হলে ব্যর্থতার কারণ।
AWS সাধারণত অবজার্বেবิลিটির জন্য CloudWatch ব্যবহার করে। কিন্তু আমার মতে স্ল্যাক ইন্টিগ্রেশনও একই উদ্দেশ্যে সার্ভ করে।
আপনার অটোমেশন ওয়ার্কফ্লোতে স্ল্যাক ইন্টিগ্রেট করার সবচেয়ে সহজ পদ্ধতি হলো একটি স্ল্যাক অ্যাপ সেট আপ করা এবং সেটি থেকে আপনার অটোমেশন ওয়ার্কফ্লো থেকে নোটিফিকেশন পাঠানো।
স্ল্যাক অ্যাপ সেট আপ করার ডকুমেন্টেশন এখানে দেখুন। প্রক্রিয়াটি সুপার ইজি এবং আপনার মিনিটের মধ্যে একটি অ্যাপ রানিং থাকবে।
অ্যাপটি তৈরি হলে, আপনি একটি WebHook URL পাবেন যা অ্যাপকে কল করে রিলেভেন্ট চ্যানেলে পোস্ট করতে ব্যবহার করতে পারেন। এই WebHook URL টি ট্র্যাক রাখুন কারণ আমরা AWS Lambda ফাংশনে এটিকে ব্যবহার করব।
AWS Lambda সেট আপ করার পদ্ধতি
এ পর্যন্ত, আমাদের একটি অ্যান্ড্রয়েড অ্যাপ বান্ডেল সাইন, বিল্ড, এবং একটি S3 বাকেটে আপলোড হয়েছে। এখন, বান্ডেলটি প্লে স্টোরের বিটা ট্রকে কিভাবে আপলোড করব সেটা বের করতে হবে।
এটি করার পদ্ধতি হলো একটি AWS Lambda সেট আপ করা যা ট্রিগার হবে যখন বান্ডেলটি S3 বাকেটে আপলোড হবে। এই ট্রিগার হলে, ল্যাম্বডা রান করবে, বান্ডেলটি ডাউনলোড করবে, সার্ভিস অ্যাকাউন্ট কী গ্র্যাব করবে, এবং বান্ডেলটি প্লে স্টোর বিটা ট্রকে আপলোড করবে।
একটি ল্যাম্বডা তৈরি করে এবং ফাইল আপলোড হলে সেটি রান করার ট্রিগার যোগ করলে, নিচের কোডটি দেখুন:
"""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') }
উপরের ল্যাম্বডা googleapiclient লাইব্রেরি এবং এর discovery মডিউল ব্যবহার করে গুগল প্লে পাব্লিশিং API-এর URL বিল্ড করবে।
পরবর্তী, ল্যাম্বডা আগে সেট আপ করা বাকেট থেকে সার্ভিস অ্যাকাউন্ট কী ডাউনলোড করবে। আপনাকে সঠিক বাকেট নাম স্পেসিফাই করতে হবে।
আপলোড সফল হয় বা ফেল সেটার উপর ভিত্তি করে, আমরা একটি স্ল্যাক মেসেজ পাঠাতে চাই। পূর্বের সেকশন থেকে Slack WebHook URL-কে ল্যাম্বডার এনভায়রনমেন্ট ভেরিয়েবলসে যোগ করুন। উপরের ফাংশনটি Python-এর os মডিউল ব্যবহার করে এনভায়রনমেন্ট ভেরিয়েবল অ্যাক্সেস করে এবং স্ল্যাকে মেসেজ পোস্ট করে।
যদি আপনার ল্যাম্বডা ফেল করে, তবে সেটি হতে পারে কারণ আপনার ল্যাম্বডার সার্ভিস অ্যাকাউন্ট কী সংরক্ষিত S3 বাকেট অ্যাক্সেস করার পারমিশন নেই। সেক্ষেত্রে, আপনি একটি এরর মেসেজ দেখবেন যা এটিকে ইন্ডিকেট করবে।
এটি ফিক্স করতে, আপনাকে সاد participó আপনার ল্যাম্বডা রোলে প্রাসঙ্গিক পারমিশন যোগ করতে হবে।
নিচের পলিসিটি আপনাকে যোগ করতে হবে:
{ "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" ] } ] }
আপনার অ্যাকাউন্টের জন্য প্রাসঙ্গিক ARN দিয়ে বাকেটের ARN রিপ্লেস করুন এবং আপনি готো।
উপসংহার
তাহলে, এটাই ছিলো। এটি কতটুকু সহজ ছিল না এবং অনেক mouving parts আছে, কিন্তু এটি একটি অটোমেশন যা আপনাকে অনেক সময় এবং পরিশ্রম বাঁচাবে।
আপনি যদি একটি টিমের অংশ হন যা ঘন ঘন নতুন অ্যাপ আপডেট রিলিজ করে, তবে আপনি চাইবেন না যে একজন ব্যক্তির অনুপস্থিতির কারণে আপডেট রিলিজ বাধা পায় যার কাজটা রিলিজ করা।
এই ধরনের অটোমেশন বিল্ড করে আপনার CI/CD ওয়ার্কফ্লো অনেক স্মুথ এবং রবাস্ট করে তোলে।
আপনি যদি এই ধরনের ব্লগ পছন্দ করেন, তবে https://redixhumayun.github.io-এ আরও পড়তে পারেন বা টুইটারে ফলো করতে পারেন।