AWS Amplify. Use existing resources - android

I have followed the tutorial:
https://aws-amplify.github.io/docs/android/start?ref=amplify-android-btn
To integrate AWS S3 with my android application.
I'm able to download a file, and everything works fine.
I've notice that when i create a enviroment, it creates a new bucket, i don't want to create a new bucket, i want to use an existing one.
I've tried to change the bucket in the awsconfiguration.json. But it does not work.
"S3TransferUtility": {
"Default": {
"Bucket": "somebucket",
"Region": "us-east-1"
}
}
AmazonS3Exception: Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: <ID>)
I don't want to create a new bucket, i want to be able to access crated buckets that share objects across other apps.

I solved. For anyone who is interested in.
For using an existing bucket, without creating a environment with amplify. The only thing i done was to add manually the file awsconfiguration.json inside the raw folder. I do not use amplify.
So, my awsconfiguration.json looks like:
{
"Version": "1.0",
"IdentityManager": {
"Default": {}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "cognito-pool-id",
"Region": "region"
}
}
},
"S3TransferUtility": {
"Default": {
"Bucket": "somebucket",
"Region": "region"
}
}
}
And to download objects from S3 i make my TransferUtility like this:
val transferUtility = TransferUtility.builder()
.context(context)
.awsConfiguration(AWSMobileClient.getInstance().configuration)
.s3Client(getAmazonS3Client())
.build()
private fun getAmazonS3Client(): AmazonS3Client{
if (amazonS3Client == null) {
amazonS3Client = AmazonS3Client(
CognitoCachingCredentialsProvider(
context,
BuildConfig.S3_POOL_ID,
Regions.US_EAST_2
),
Region.getRegion(Regions.US_EAST_2)
)
}
return amazonS3Client!!
}

Related

AWSMobileClient: Access Token not refreshed automatically

Documentation says: "The tokens are automatically refreshed by the library when necessary.". I call
AWSMobileClient.getInstance().getTokens().getAccessToken().getTokenString();
everytime before calling the API with AccessToken.
Here is what my awsconfiguration file looks like
`{
"IdentityManager": {
"Default": {}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "ap-xxxxx-1:2xxxxxx-xxxx-xxxx-xxxx-7xxxxxxxxxx",
"Region": "ap-xxxxx-1"
}
}
},
"CognitoUserPool": {
"Default": {
"PoolId": "ap-xxxxx-1_xxxxxxxxx",
"AppClientId": "xxxxxxxxxxxxxxxxxxxxx",
"Region": "ap-xxxxx-1"
}
}
After an hour, API returns 401(Authentication Error).
And AWSMobileClient.getInstance().getTokens().getAccessToken().getTokenString(); returns an error
AWSMobileClient: Tokens are invalid, please sign-in again.
java.lang.Exception: No cached session.
Am I doing something wrong?
PS: I have not used Amplify CLI.
So the problem was I was calling the getTokens() method from the main thread and it returned the tokens without refreshing. Then I moved the getTokens call inside the AWSMobileClient.getInstance().initialize(..) call and I got refreshed tokens whenever required.

How to setup different configuration(awsconfiguration.json) with AWSMobileClient for debug and release build types

I want to have different configuration for debug and release builds. All the configuration is stored inside awsconfiguration.json, for example I have two different config files how can I set which file should be used.
When using AWSMobileClient.getInstance() it gets default configuration from file awsconfiguration.json
Configuration file example:
{
"Version": "1.0",
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "DIFFERENT_VALUES",
"Region": "DIFFERENT_VALUES"
}
}
},
"IdentityManager": {
"Default": {}
},
"CognitoUserPool": {
"Default": {
"AppClientSecret": "DIFFERENT_VALUES",
"AppClientId": "DIFFERENT_VALUES",
"PoolId": "DIFFERENT_VALUES",
"Region": "DIFFERENT_VALUES"
}
}
}
Update
There is option to use different awsconfiguration.json by puting different files in main\res\raw and release\res\raw, for example by following this answer and it works.
But I'm wondering whether there is an option to do it programmatically.
This can also be acheived by setting the configuration value in AWSConfiguration and then initializing the AWSMobileClient.
AWSConfiguration awsConfiguration = new AWSConfiguration(context);
awsConfiguration.setConfiguration("Stage"); // BuildConfig can be used here.
AWSMobileClient.getInstance().initialize(context, awsConfiguration, new Callback<UserStateDetails>() {
#Override
public void onResult(UserStateDetails userStateDetails) {
}
#Override
public void onError(Exception e) {
}
});
And the awsconfiguration.json file can be updated as below
{
"Version": "1.0",
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "DIFFERENT_VALUES",
"Region": "DIFFERENT_VALUES"
},
"Stage": {
"PoolId": "STAGE_VALUES",
"Region": "STAGE_VALUES"
}
}
},
"IdentityManager": {
"Default": {},
"Stage": {}
},
"CognitoUserPool": {
"Default": {
"AppClientSecret": "DIFFERENT_VALUES",
"AppClientId": "DIFFERENT_VALUES",
"PoolId": "DIFFERENT_VALUES",
"Region": "DIFFERENT_VALUES"
},
"Stage": {
"AppClientSecret": "STAGE_VALUES",
"AppClientId": "STAGE_VALUES",
"PoolId": "STAGE_VALUES",
"Region": "STAGE_VALUES"
}
}
}
I've been trying to achieve something similar; selecting an AWS configuration at runtime based on a selected profile. I got it partially working by hacking the AWS SDK but then stumbled across release notes for AWS SDK version 2.11.0. Quoting:
Added the option of passing the configuration as an in-memory object (i.e. [String: Any]/NSDictionary) instead of the default awsconfiguration.json through the new API
I've also found it documented(!) in the amplify getting started guide here.
So since 9th September 2019 it IS possible to select an AWS configuration at runtime.
Edit: Just noticed that this question is for Android rather than iOS. I'm not an Android developer but a quick searched revealed something similar in AWS Android SDK release 2.13.6 (7th June 2019). Quoting the release notes:
Add AWSConfiguration(JSONObject) constructor to construct a AWSConfiguration object from the configuration passed via a JSONObject
... which looks promising.
This can be done with source sets; eg. directories main & debug or directories debug & release, where res/raw or assets are not being processed by AAPT2. Adding credentials alike that is only suggested for internal use, because they can be easily extracted from the package.
Abhishek's answer is my favorite of these. But if you're using Amplify (as I am), while it's possible to put multiple configurations into a single file, I've not found a way of selecting between them.
So, although it's not an exact answer to the question, in Amplify you can select between multiple, self-contained configuration files like this:
When you set up Amplify:
Amplify.addPlugin(AWSCognitoAuthPlugin())
// and whatever other plugins you'll need...
Amplify.configure(AmplifyConfiguration.fromConfigFile(applicationContext, getConfigResourceId(applicationContext)), applicationContext)
And also add:
private fun getConfigResourceId(context: Context): Int = context.resources.getIdentifier("YourConfigFileName", "raw", context.packageName)

AWS s3 - > lambda -> sns = How to send url link with new image to android app?

New S3 item triggers lambda function. I'd like to somehow extract it's URL and pass it to sns as a link or something that can be opened from notification on Android phone. I can send notifications to phone at the moment but need to pass new element from S3. Does anyone have any ideas and is it possible to achieve like that?
Here's the code from my lambda function. It's in mess since i've been trying different combinations to attempt this:
import logging
import boto3
sns = boto3.client('sns')
s3 = boto3.client('s3')
# Change topic, qos and payload
def lambda_handler(event, context):
# retrieve bucket name and file_key from the S3 event
bucket_name = event['Records'][0]['s3']['bucket']['name']
file_key = event['Records'][0]['s3']['object']['key']
#logger.info('Reading {} from {}'.format(file_key, bucket_name))
presigned_url = s3.genereate_presigned_url(
'get_object',
Params = {'Bucket': bucket_name, 'Key': file_key}
)
sns.publish(
TargetArn='arn:aws:sns:eu...',
Message=presigned_url
)
error:
Response:
{
"errorMessage": "'S3' object has no attribute
'genereate_presigned_url'",
"errorType": "AttributeError",
"stackTrace": [
[
"/var/task/lambda_function.py",
14,
"lambda_handler",
"presigned_url = s3.genereate_presigned_url("
],
[
"/var/runtime/botocore/client.py",
555,
"__getattr__",
"self.__class__.__name__, item)"
]
]
}
Thanks to dpwrussell, I was able to extract url from test function and learned more about lambda and AWS. Below is updated version of the code and lambda trigger test.
from __future__ import print_function
import logging
import boto3
logger = logging.getLogger()
logger.setLevel(logging.INFO)
sns = boto3.client('sns')
s3 = boto3.client('s3')
# Change topic, qos and payload
def lambda_handler(event, context):
# retrieve bucket name and file_key from the S3 event
bucket_name = event['Records'][0]['s3']['bucket']['name']
print(bucket_name)
file_key = event['Records'][0]['s3']['object']['key']
#logger.info('Reading {} from {}'.format(file_key, bucket_name))
print('this will also show up in cloud watch')
logger.info('got event{}'.format(bucket_name))
logger.info('got event{}'.format(file_key))
generate_presigned_url = s3.genereate_presigned_url(
'get_object',
Params = {'Bucket': bucket_name, 'Key': file_key}
)
sns.publish(
TargetArn='arn.........',
Message=generate_presigned_url
)
Test event:
{
"Records": [
{
"s3": {
"bucket": {
"name": "mybucket"
}
},
"object": {
"key": "Example.json.gz"
}
}
]
}
That's not the interface to generate_presigned_url.
It's:
presigned_url = s3.generate_presigned_url(
'get_object',
Params = {'Bucket': bucket_name, 'Key': file_key}
)
You also have a problem with your input. Your input needs to have a structure like this. Otherwise your lambda function will fail with that KeyError that your getting when trying to read these parameters from the event.
{
"Records": [
"s3": {
"bucket": {
"name: "mybucketname"
},
"object": {
"key": "mybucketkey"
}
}
]
}
Thank you #Marszal and #dpwrussell.
I am new to python and this post helped me to get the desired output. I am using Python 3.8 Runtime and was getting error with generate_presigned_url. Error looks like:
[ERROR] AttributeError: 'S3' object has no attribute 'genereate_presigned_url'
Also, I had to fetch file size. So I tried this simple approach to get the final URL and it is working.
import boto3
import logging
import json
sns = boto3.client('sns')
s3 = boto3.client('s3')
def lambda_handler(event, context):
# retrieve bucket name, file_key and size from the S3 event
bucket_name = event['Records'][0]['s3']['bucket']['name']
print("Bucket Name: "+bucket_name)
file_key = event['Records'][0]['s3']['object']['key']
print("File Key: "+file_key)
file_size = event['Records'][0]['s3']['object']['size']
print("File Size: "+str(file_size)+"kb")
s3url = "s3://"+bucket_name+"/"+file_key
print("S3 URL: "+s3url)

Failed to read S3TransferUtility please check your setup or awsconfiguration.json file

I am a newbie using AWS sdk for video transfer.But i am getting the error "Failed to read S3TransferUtility please check your setup or awsconfiguration.json file". Here is my code.
In my manifest file i have
<service android:name="com.amazonaws.mobileconnectors.s3.transferutility.TransferService" android:enabled="true" />
In my oncreate i am doing this.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_upload_post);
AWSMobileClient.getInstance().initialize(this).execute();
transferUtility =
TransferUtility.builder()
.context(this)
.awsConfiguration(AWSMobileClient.getInstance().getConfiguration())
.s3Client(new AmazonS3Client(AWSMobileClient.getInstance().getCredentialsProvider()))
.build();
}
The exception comes at .build. I debugged the code and it picks up the config file located at in folder perfectly cause i can see the data in debug but i think the transferutility.TransferService is not running. Can someone please help. Thanx
For some reason the auto generated "awsconfiguration" file doesn't include the most important section called "S3TransferUtility". So you have to add it manually.
Your "awsconfiguration.json" file should look something like this:
{
"UserAgent": "MobileHub/1.0",
"Version": "1.0",
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "us-east-1:<RANDOM-GUID>",
"Region": "us-east-1"
}
}
},
"IdentityManager": {
"Default": {}
},
"PinpointAnalytics": {
"Default": {
"AppId": "<UNIQUE ID>",
"Region": "us-east-1"
}
},
"PinpointTargeting": {
"Default": {
"Region": "us-east-1"
}
},
"S3TransferUtility": {
"Default": {
"Bucket": "<YOUR BUCKET NAME>",
"Region": "us-east-1"
}
}
}
In my awsconfiguration.json i add below lines then it's started working
"S3TransferUtility": {
"Default": {
"Bucket": "<YOUR BUCKET NAME>",
"Region": "us-east-1"
}
}
Add awsconfiguration.json on your project and change pool id and region attributes. You can read more about it here.

How to send an list to API using retrofit2

I developed an API using EVE.
This is the schema:
central_schema = {
'name': {
'type': 'string',
'required': True,
},
'id_account': {
'type': 'list',
}
}
I'm trying to send a list using retrofit 2. I tried the API using POSTMAN. Everytime I got this response:
id account "must be of list type"
I used many types of requests (PATCH, POST, PUT), but I still get the same error.
You can create Model class like below:
public class Model{
public String name;
public List<String> id_account;
}
And use it in retrofit 2.
It will produce below json:
{
"name": "xyz",
"id_account" : [
"1",
"2"
]
}

Categories

Resources