I have a back-end that I have written with Laravel and I am currently writing and Android app which is doing calls to my back-end.
I have some png's and pdf's stored in s3 buckets in my aws account. I need to get the images and documents from the bucket and store them locally on the device as well as displaying them.
I also need to send new png's from the phone to be stored in the s3 bucket.
What is the best way to go around doing this. Are there any useful libraries. I have already added Picasso but that only helps with displaying the image not getting from/storing in the s3 bucket.
You can use the AWS Android SDK for S3. You can consume it in gradle via maven as:
dependencies {
compile 'com.amazonaws:aws-android-sdk-s3:2.6.+'
}
For example to upload a file to S3:
import android.app.Activity;
import android.util.Log;
import com.amazonaws.mobile.client.AWSMobileClient;
import com.amazonaws.mobileconnectors.s3.transferutility.TransferUtility;
import com.amazonaws.mobileconnectors.s3.transferutility.TransferState;
import com.amazonaws.mobileconnectors.s3.transferutility.TransferObserver;
import com.amazonaws.mobileconnectors.s3.transferutility.TransferListener;
import com.amazonaws.services.s3.AmazonS3Client;
import java.io.File;
public class YourActivity extends Activity {
public void uploadData() {
// Initialize AWSMobileClient if not initialized upon the app startup.
// AWSMobileClient.getInstance().initialize(this).execute();
TransferUtility transferUtility =
TransferUtility.builder()
.context(getApplicationContext())
.awsConfiguration(AWSMobileClient.getInstance().getConfiguration())
.s3Client(new AmazonS3Client(AWSMobileClient.getInstance().getCredentialsProvider()))
.build();
TransferObserver uploadObserver =
transferUtility.upload(
"s3Folder/s3Key.txt",
new File("/path/to/file/localFile.txt"));
uploadObserver.setTransferListener(new TransferListener() {
#Override
public void onStateChanged(int id, TransferState state) {
if (TransferState.COMPLETED == state) {
// Handle a completed upload.
}
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
float percentDonef = ((float)bytesCurrent/(float)bytesTotal) * 100;
int percentDone = (int)percentDonef;
Log.d("MainActivity", " ID:" + id + " bytesCurrent: " + bytesCurrent + " bytesTotal: " + bytesTotal + " " + percentDone + "%");
}
#Override
public void onError(int id, Exception ex) {
// Handle errors
}
});
// If your upload does not trigger the onStateChanged method inside your
// TransferListener, you can directly check the transfer state as shown here.
if (TransferState.COMPLETED == uploadObserver.getState()) {
// Handle a completed upload.
}
}
}
For more information:
https://docs.aws.amazon.com/aws-mobile/latest/developerguide/add-aws-mobile-user-data-storage.html#add-aws-user-data-storage-upload
https://docs.aws.amazon.com/aws-mobile/latest/developerguide/how-to-storage.html
AWS has a set of libraries that you could use to get and store in the S3 bucket.
You should check: https://docs.aws.amazon.com/aws-mobile/latest/developerguide/getting-started.html
For upload file to s3
String ACCESS_KEY="****************",
SECRET_KEY="****************",
MY_BUCKET="bucket_name",
OBJECT_KEY="unique_id";
AWSCredentials credentials = new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY);
AmazonS3 s3 = new AmazonS3Client(credentials);
java.security.Security.setProperty("networkaddress.cache.ttl" , "60");
s3.setRegion(Region.getRegion(Regions.AP_SOUTHEAST_1));
s3.setEndpoint("https://s3-ap-southeast-1.amazonaws.com/");
List<Bucket> buckets=s3.listBuckets();
for(Bucket bucket:buckets){
Log.e("Bucket ","Name "+bucket.getName()+" Owner "+bucket.getOwner()+ " Date " + bucket.getCreationDate());
}
Log.e("Size ", "" + s3.listBuckets().size());
TransferUtility transferUtility = new TransferUtility(s3, getApplicationContext());
UPLOADING_IMAGE=new File(Environment.getExternalStorageDirectory().getPath()+"/Screenshot.png");
TransferObserver observer = transferUtility.upload(MY_BUCKET,OBJECT_KEY,UPLOADING_IMAGE);
observer.setTransferListener(new TransferListener() {
#Override
public void onStateChanged(int id, TransferState state) {
// do something
progress.hide();
path.setText("ID "+id+"\nState "+state.name()+"\nImage ID "+OBJECT_KEY);
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
int percentage = (int) (bytesCurrent / bytesTotal * 100);
progress.setProgress(percentage);
//Display percentage transfered to user
}
#Override
public void onError(int id, Exception ex) {
// do something
Log.e("Error ",""+ex );
}
});
For downloading image
https://github.com/jontyankit/Glide-Amazon-Image-Load
Related
I'm able to store files with the AWS Amplify Storage category. However, they all are being stored in the top of the public folder in my bucket. How do I specify a path inside the public folder?
I referenced both the JavaScript and Android documentation for Amplify storage.
Here's my code.
Amplify.Storage.uploadFile(
"filenmae.txt",
filename.getAbsolutePath(),
new ResultListener<StorageUploadFileResult>() {
#Override
public void onResult(StorageUploadFileResult result) {
Log.i("StorageQuickStart", "Successfully uploaded: " + result.getKey());
}
#Override
public void onError(Throwable error) {
Log.e("StorageQuickstart", "Upload error.", error);
}
}
);
If you want to upload A file to a specific folder, then all you have to do is add the folder name path prefix to your 1st key parameter of the method Amplify.Storage.uploadFile().
For Example
let's say you want to upload your files in a folder that have name "game".
// Name of your folder with '/' in the end to make it like path prefix
String folderGame = "game/";
// here we just adding it before the name of your file
String key = folderGame +"filenmae.txt";
/*
* Now the value in key will look like "game/filenmae.txt" and
* pass it in method as first parameter where you were passing
* the name previously.
*/
Amplify.Storage.uploadFile(
key,
filename.getAbsolutePath(),
new ResultListener<StorageUploadFileResult>() {
#Override
public void onResult(StorageUploadFileResult result) {
Log.i("StorageQuickStart", "Successfully uploaded: " + result.getKey());
}
#Override
public void onError(Throwable error) {
Log.e("StorageQuickstart", "Upload error.", error);
}
}
);
Extra
For the other methods like download, remove etc., you have to do the same thing to access these files. Just add the prefix.
I have this problem in the onError of the upload: Unable to execute HTTP request: Write error: ssl=0x7b4a65b280: I/O error during system call, Connection reset by peer
I don't know why, also I've followed the guidelines.
I have <service android:name="com.amazonaws.mobileconnectors.s3.transferutility.TransferService" android:enabled="true" /> in the manifest
I Have implementation 'com.amazonaws:aws-android-sdk-s3:2.2.+' in the internal gradle
My code:
public void upload(String path,File file) {
path=path.replace("/storage/emulated/0/blablabla/","");
// Initialize the Amazon Cognito credentials provider
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(),
"blablabla", // Identity pool ID
Regions.EU_WEST_1 // Region
);
AmazonS3 s3 = new AmazonS3Client(credentialsProvider);
TransferUtility transferUtility = new TransferUtility(s3, getApplicationContext());
final TransferObserver observer = transferUtility.upload(
"blablabla", //this is the bucket name on S3
path, //this is the path and name
file //path to the file locally
);
observer.setTransferListener(new TransferListener() {
#Override
public void onStateChanged(int id, TransferState state) {
if (state.equals(TransferState.COMPLETED)) {
Log.d("AMAZON","si");
} else if (state.equals(TransferState.FAILED)) {
//Failed
Log.d("AMAZON","no");
}
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
}
#Override
public void onError(int id, Exception ex) {
Log.d("AMAZON",ex.getMessage());
}
});
}
You are on a really antiquated version of the SDK. Please upgrade to the latest version 2.16.6 and try uploading using the instruction here :
https://aws-amplify.github.io/docs/sdk/android/storage#upload-a-file
I'm using the aws sample code to upload files to the S3, but when they get uploaded they come with no access for anyone, even with the bucket made Public for everyone, the only way to read it is to manually set the files on the S3 console to give public access.
MyService:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && intent.getStringExtra(INTENT_KEY_NAME) != null) {
final String key = intent.getStringExtra(INTENT_KEY_NAME);
final File file = (File) intent.getSerializableExtra(INTENT_FILE);
final String transferOperation = intent.getStringExtra(INTENT_TRANSFER_OPERATION);
TransferObserver transferObserver;
switch (transferOperation) {
case TRANSFER_OPERATION_DOWNLOAD:
Log.d(TAG, "Downloading " + key);
transferObserver = transferUtility.download("aws-MYBUCKET", key, file);
transferObserver.setTransferListener(new DownloadListener());
break;
case TRANSFER_OPERATION_UPLOAD:
Log.d(TAG, "Uploading " + key);
transferObserver = transferUtility.upload("aws-MYBUCKET", key, file);
transferObserver.setTransferListener(new UploadListener());
break;
}
return START_STICKY;
} else return START_NOT_STICKY;
You should create a Bucket Policy. This can grant public access for the whole bucket, or a portion of the bucket.
From Bucket Policy Examples - Amazon Simple Storage Service:
{
"Version":"2012-10-17",
"Statement":[
{
"Sid":"AddPerm",
"Effect":"Allow",
"Principal": "*",
"Action":["s3:GetObject"],
"Resource":["arn:aws:s3:::examplebucket/*"]
}
]
}
This is preferable to granting access on individual objects.
I am trying to integrate stripe into my android application with the server code set up in Backendless as a Custom API Service. After charging the card, with a successful call back method, I am not able to see that in my payments list on my stripe dashboard. Not sure where the problem is. Any suggestions will be appreciated.Below is what I have so far:
ChargeItem://Charge Class
package com.mbaas.service;
public class ChargeItem {
public String token;
public int price;
public String description;
}
ChargeService //Backendless Service
import com.stripe.Stripe;
import com.stripe.exception.StripeException;
import com.stripe.model.Charge;
import java.util.HashMap;
import java.util.Map;
public class ChargeService implements IBackendlessService
{
public boolean makeCharge(ChargeItem charges){
Stripe.apiKey = "my stripe secret key";
// Get the credit card details submitted by the form
String token = charges.token;
double price = charges.price;
String desc = charges.description;
String userId = charges.userId;
String orderId = charges.orderId;
// Create a charge: this will charge the user's card
try {
Map<String, Object> chargeParams = new HashMap<String, Object>();
chargeParams.put("orderId",orderId);
chargeParams.put("userId",userId);
chargeParams.put("amount", price); // Amount in cents
chargeParams.put("currency", "usd");
chargeParams.put("source", token);
chargeParams.put("description", desc);
#SuppressWarnings("unused")
Charge charge = Charge.create(chargeParams);
}
catch (StripeException e) {
// The card has been declined
return false;
}
return true;
}
}
//My stripe token call back method
private void convertCardToToken(Card card, final Orders order){
Stripe stripe = new Stripe(getApplicationContext(), CustomApplication.PUBLISHABLE_KEY);
stripe.createToken(
card,
new TokenCallback() {
public void onSuccess(Token token) {
// Send token to your server
ChargeItem chargeItem = new ChargeItem();
chargeItem.setToken(token.getId());
chargeItem.setOrderId(order.getObjectId());
chargeItem.setPrice(order.getOrder_price());
chargeItem.setUserName(order.getOwnerId());
chargeItem.setDescription("Delivery Fee");
ChargeService.initApplication();
ChargeService chargeService = ChargeService.getInstance();
chargeService.makeChargeAsync(chargeItem, new AsyncCallback<Boolean>() {
#Override
public void handleResponse(Boolean response) {
Toast.makeText(getApplicationContext(),
"Payment Successful",
Toast.LENGTH_LONG
).show();
}
#Override
public void handleFault(BackendlessFault fault) {
Toast.makeText(getApplicationContext(), fault.getMessage(),
Toast.LENGTH_LONG
).show();
}
});
}
public void onError(Exception error) {
// Show localized error message
Toast.makeText(CheckoutActivity.this,
error.getLocalizedMessage(),
Toast.LENGTH_LONG
).show();
}
}
);
}
I'm not familiar with Backendless so I cannot provide much help here, but there a few issues with your code:
price is a double. To avoid rounding errors, all amounts in Stripe's API are in cents (or more generally, in the smallest unit for the currency you're using), so price should be an int.
userId and orderId are not valid parameters when creating a charge. You likely want to pass these variables as metadata values.
To help you debug further, you should also check your logs in your Stripe account's dashboard at https://dashboard.stripe.com/test/logs?method=not_get. You should see requests to POST /v1/tokens (sent by your Android app) and requests to POST /v1/charges (sent by Backendless).
I'm trying to figure out what is the cause of this crash when uploading on Amazon S3 bucket.
Log is:
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean com.amazonaws.mobileconnectors.s3.transferutility.TransferService$NetworkInfoReceiver.isNetworkConnected()' on a null object reference
at com.amazonaws.mobileconnectors.s3.transferutility.TransferService.execCommand(TransferService.java:287)
at com.amazonaws.mobileconnectors.s3.transferutility.TransferService$UpdateHandler.handleMessage(TransferService.java:224)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.os.HandlerThread.run(HandlerThread.java:61)
Is there is something wrong on my code?
public AmazonTransferUtility uploadFileToAmazonS3(String data, Date date){
generateTextFileFromString(data, date);
File jsonFile = new File(getDataPath(), textName);
TransferObserver observer = transferUtility.upload(
textBucketName,
mUUID + File.separator + date.getTime() + textName ,
jsonFile
);
mListener.onAsyncStart();
observer.setTransferListener(new TransferListener() {
#Override
public void onStateChanged(int id, TransferState state) {
try {
if (state.toString().equals("COMPLETED")) {
deleteFile(textName);
if (mListener != null) {
JSONObject result = new JSONObject();
result.put("result", state.toString());
mListener.onAsyncSuccess(result);
}
}
else if (state.toString().equals("FAILED") ||
state.toString().equals("UNKNOWN")
){
mListener.onAsyncFail(id, state.toString());
}
else{
Log.i(TAG, "S3 TransferState :" + state.toString());
}
}catch (JSONException e){
Log.e(TAG, e.getLocalizedMessage());
}
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
if (bytesCurrent == bytesTotal){
Log.i(TAG, "Completed");
}
else{
Log.i(TAG, "Current bytes: " + bytesCurrent + " Of bytesTotal : " + bytesTotal);
}
}
#Override
public void onError(int id, Exception ex) {
mListener.onAsyncFail(id,ex.getMessage());
}
});
return this;
}
And if ever how can I catch this error so that my app stop crashing and just cancel my uploading task.
BTW.
That crash is intermittent and ratio is 1 out of 5 successful sync
This doesn't appear to be something you are doing, it's inside the AWS SDK code. The implication of that NPE is a flaky network. It's been reported to Amazon on github (and confirmed in another ticket) and it appears rolling back one version in the SDK (v2.2.13) may help.
That also makes sense given the changes made in 2.2.14, which are related to S3 transfer and the network.
I'd suggest following those tickets (please don't +1). It's reasonable to expect they will fix it within a week.
Here's a workaround until the bug is fixed, just fire this up in your application's onCreate, or well before any upload activity starts:
/**
* work around for a bug:
* http://stackoverflow.com/questions/36587511/android-amazon-s3-uploading-crash
*/
public static void startupTranferServiceEarlyToAvoidBugs(Context context) {
final TransferUtility tu = new TransferUtility(
new AmazonS3Client((AWSCredentials)null),
context);
tu.cancel(Integer.MAX_VALUE - 1);
}
essentially what this does is tell the TransferService to start up and initialize it's member variables so that it doesn't enter the condition where it tries to service commands before it's ready to.