Android and AWS S3 - android

i am creating an Android App within AWS mobile Hub, i would like to do know is it possible when a user Signs up to my Application that an S3-Bucket or even a Folder within an S3 bucket is created only for that user account ?

Yes, you can use PutObjectRequest(bucketName, keyName, file) to achieve your use case.
Create S3 folder
With AWS S3 Java SDK , just add "/" at the end of the key name, it will create empty folder.
var folderKey = key + "/"; //end the key name with "/"
Sample code:
final InputStream im = new InputStream() {
#Override
public int read() throws IOException {
return -1;
}
};
final ObjectMetadata om = new ObjectMetadata();
om.setContentLength(0L);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, im, om);
s3.putObject(putObjectRequest);

Related

How do I download a file on both Android X and iOS that is publicly available, using Xamarin.Forms?

Looking at this issue xamarin/Essentials#1322, how do I download a file on both Android ( versions 6-10, Api 23-29 ) and iOS ( version 13.1+ ) that is publicly available (share-able to other apps, such as Microsoft Word). I don't need to give write access to the other apps, just read-only is ok if it must be restricted.
I get the following exception:
[Bug] Android.OS.FileUriExposedException: file:///data/user/0/{AppBundleName}/cache/file.doc exposed beyond app through Intent.getData()
With the following code.
public static string GetCacheDataPath( string fileName ) => Path.Combine(Xamarin.Essentials.FileSystem.CacheDirectory, fileName);
public static FileInfo SaveFile( string filename, Uri link )
{
using var client = new WebClient();
string path = GetCacheDataPath(filename);
DebugTools.PrintMessage(path);
client.DownloadFile(link, path);
return new FileInfo(path);
}
public async Task Test(Uri link)
{
LocalFile path = await SaveFile("file.doc", link).ConfigureAwait(true);
var url = new Uri($"ms-word://{path.FullName}", UriKind.Absolute);
await Xamarin.Essentials.Launcher.OpenAsync(url).ConfigureAwait(true);
}
With this answer, I created a FileService interface and it works with local private files but I am unable to share the files. Starting with Android Q (10 / Api 29), the following is deprecated.
string path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath; // deprecated
I get the following exception:
System.UnauthorizedAccessException: Access to the path '/storage/emulated/0/Download/file.doc' is denied. ---> System.IO.IOException: Permission denied
I haven't found any way yet to get a public path for Android 10 with Xamarin.Forms. I've looked at the Android Docs for Content providers but it's in Java, and I can't get it working in C# yet.
Any help would be greatly appreciated.
I did find a Solution
Found a fix
For Android
public Task<System.IO.FileInfo> DownloadFile( Uri link, string fileName )
{
if ( link is null )
throw new ArgumentNullException(nameof(link));
using System.Net.WebClient client = new System.Net.WebClient();
// MainActivity is the class that loads the application.
// MainActivity.Instance is a property that you set "Instance = this;" inside of OnCreate.
Java.IO.File root = MainActivity.Instance.GetExternalFilesDir(MediaStore.Downloads.ContentType);
string path = Path.Combine(root.AbsolutePath, fileName);
client.DownloadFile(link, path);
return Task.FromResult(new System.IO.FileInfo(path));
}
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
internal static MainActivity Instance { get; private set; }
protected override void OnCreate(Bundle savedInstanceState)
{
...
Instance = this;
...
}
...
}
For iOS
public Task<System.IO.FileInfo> DownloadFile( Uri link, string fileName )
{
if ( link is null )
throw new ArgumentNullException(nameof(link));
using System.Net.WebClient client = new System.Net.WebClient();
string path = Path.Combine(Xamarin.Essentials.FileSystem.CacheDirectory, fileName)
client.DownloadFile(link, path);
return Task.FromResult(new System.IO.FileInfo(path));
}
public async Task Share()
{
// back in shared project, choose a file name and pass the link.
System.IO.FileInfo info = await DependencyService.Get<IDownload>().DownloadFile(new Uri("<enter site>", "file.doc").ConfigureAwait(true);
ShareFile shareFile = new ShareFile(info.FullName, "doc"); // enter the file type / extension.
var request = new ShareFileRequest("Choose the App to open the file", shareFile);
await Xamarin.Essentials.Share.RequestAsync(request).ConfigureAwait(true);
}
Note that for iOS, due to Apple's infinite wisdom... I cannot share the file directly with another app as I can on Android. Sandboxing is good for security but in this case, how they implemented it, it limits options. Both Applications must be pre-registered / pre-allocated in an "App Group" to share files directly. See this Article and the Apple Docs for more information.

Amazon AWS S3 file upload. How to set file permissions?

I'm uploading a file using Amazon's AWS SDK (S3), and everything is working fine. Below is my code:
final AWSCredentials credentials = new AWSCredentials() {
#Override
public String getAWSAccessKeyId() {
return "...myAccessKey...";
}
#Override
public String getAWSSecretKey() {
return "...mySecretKey...";
}
};
final StaticCredentialsProvider credentialsProvider = new StaticCredentialsProvider(credentials);
final TransferManager transferManager = new TransferManager(credentialsProvider);
final Upload upload = transferManager.upload(Config.AWS_IMAGE_BUCKET, "images/" + file.getName(), file);
Problem is, whenever I upload something like this, the permissions are not set to public, so I can't use them in my app.
How can I set the file permissions from my code so that it's viewable by public?
Thanks!
You need to provide a PutObjectRequest with the ACLs you want when you call upload.
Choose appropriate ACL policy when you put file in to the bucket.
It can be one of the following option:
1) ACL_AUTHENTICATED_READ
Allow read access to authenticated users.
2) ACL_PRIVATE
Allows only private access to the file.
3) ACL_PUBLIC_READ.
Allows public read access to the file.
4) ACL_PUBLIC_READ_WRITE
Allows public read write access to the file when you write files onto the bucket.

Using Google Cloud Storage JSON api in android

I want to upload image on Google Cloud Storage from my android app. For that I searched and found that GCS JSON Api provides this feature. I did a lot of research for Android sample which demonstrates its use. On the developer site they have provided code example that only support java. I don't know how to use that API in Android. I referred this and this links but couldn't get much idea. Please guide me on how i can use this api with android app.
Ok guys so I solved it and got my images being uploaded in Cloud Storage all good.
This is how:
Note: I used the XML API it is pretty much the same.
First, you will need to download a lot of libraries.
The easiest way to do this is create a maven project and let it download all the dependencies required. From this sample project :
Sample Project
The libraries should be:
Second, you must be familiar with Cloud Storage using the api console
You must create a project, create a bucket, give the bucket permissions, etc.
You can find more details about that here
Third, once you have all those things ready it is time to start coding.
Lets say we want to upload an image:
Cloud storage works with OAuth, that means you must be an authenticated user to use the API. For that the best way is to authorize using Service Accounts. Dont worry about it, the only thing you need to do is in the API console get a service account like this:
We will use this service account on our code.
Fourth, lets write some code, lets say upload an image to cloud storage.
For this code to work you must put your key generated in step 3 in assets folder, i named it "key.p12".
I don't recommend you to do this on your production version, since you will be giving out your key.
try{
httpTransport= new com.google.api.client.http.javanet.NetHttpTransport();
//agarro la key y la convierto en un file
AssetManager am = context.getAssets();
InputStream inputStream = am.open("key.p12"); //you should not put the key in assets in prod version.
//convert key into class File. from inputstream to file. in an aux class.
File file = UserProfileImageUploadHelper.createFileFromInputStream(inputStream,context);
//Google Credentianls
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(Collections.singleton(STORAGE_SCOPE))
.setServiceAccountPrivateKeyFromP12File(file)
.build();
String URI = "https://storage.googleapis.com/" + BUCKET_NAME+"/"+imagename+".jpg";
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);
GenericUrl url = new GenericUrl(URI);
//byte array holds the data, in this case the image i want to upload in bytes.
HttpContent contentsend = new ByteArrayContent("image/jpeg", byteArray );
HttpRequest putRequest = requestFactory.buildPutRequest(url, contentsend);
com.google.api.client.http.HttpResponse response = putRequest.execute();
String content = response.parseAsString();
Log.d("debug", "response is:"+response.getStatusCode());
Log.d("debug", "response content is:"+content);} catch (Exception e) Log.d("debug", "Error in user profile image uploading", e);}
This will upload the image to your cloud bucket.
For more info on the api check this link Cloud XML API
Firstly, You should get the below information by registering your application in the GCP console.
private final String pkcsFile = "xxx.json";//private key file
private final String bucketName = "your_gcp_bucket_name";
private final String projectId = "your_gcp_project_id";
Once you get the credentials, you should put the private key (.p12 or .json) in your assets folder. I'm using JSON format private key file. Also, you should update the image location to upload.
#RequiresApi(api = Build.VERSION_CODES.O)
public void uploadImageFile(String srcFileName, String newName) {
Storage storage = getStorage();
File file = new File(srcFileName);//Your image loaction
byte[] fileContent;
try {
fileContent = Files.readAllBytes(file.toPath());
} catch (IOException e) {
e.printStackTrace();
return;
}
if (fileContent == null || fileContent.length == 0)
return;
BlobInfo.Builder newBuilder = Blob.newBuilder(BucketInfo.of(bucketName), newName);
BlobInfo blobInfo = newBuilder.setContentType("image/png").build();
Blob blob = storage.create(blobInfo, fileContent);
String bucket = blob.getBucket();
String contentType = blob.getContentType();
Log.e("TAG", "Upload File: " + contentType);
Log.e("File ", srcFileName + " uploaded to bucket " + bucket + " as " + newName);
}
private Storage getStorage() {
InputStream credentialsStream;
Credentials credentials;
try {
credentialsStream = mContext.getAssets().open(pkcsFile);
credentials = GoogleCredentials.fromStream(credentialsStream);
} catch (IOException e) {
e.printStackTrace();
return null;
}
return StorageOptions.newBuilder()
.setProjectId(projectId).setCredentials(credentials)
.build().getService();
}

Upload a file from Android to Drupal via Services Module

I tried to upload an image from Android Device to a Drupal Website
I used the Service module on Drupal side with method file.create.
The problem is that the files has been broken after the download.
The Files are smaller.
The filemime setting has n effect.
Javaside:
public Map saveFile(String localFilePath, String serverpath) throws XmlRpcException, IOException{
HashMap<String, Object> account = new HashMap<String, Object>();
File localFile = new File(localFilePath);
Log.w("XMLRPC", "FILENAME "+localFile.getName() + " original "+localFile.length());
String fileAsString = readFile(localFilePath);
// Sending side
byte[] data = fileAsString.getBytes("UTF-8");
byte[] base64 = Base64.encode(data,Base64.URL_SAFE);
account.put("file", base64);
account.put("filename", localFile.getName());
account.put("filepath", serverpath +"/"+ localFile.getName());
// account.put("filemime", "application/x-compressed");
account.put("filesize", Integer.parseInt(localFile.length()+""));//String.valueOf(localFile.length()));
Vector<Object> params = new Vector<Object>();
params.add(account);
return (Map) xmlRpcClient.execute(METHOD_FILE_CREATE, params);
}
Well, if you are not using a native android app for your Drupal site, you do not need any other 'interface' to upload the file! It should work as if you are uploading the file from desktop!

How to use POST method to upload file in google-api-java-client?

google-api-java-client is a good web service api client on Android, however I mean a problem and spend lots of time on it.
I want to upload a file via POST method, so I study the google-drive API source code, but it uses the media uploader to upload file to google drive.
so how to upload a file via POST method in google-api-java-client?
for example Imgur upload API method has two require parameter.
suppose a upload file API written in google-api-java-client like this, but i have no idea how should I fill in the 'image' field which marked ???
public class ImgurImage extends GenericJson {
#com.google.api.client.util.Key("key")
private String mKey;
#com.google.api.client.util.Key("image")
private ??? mImage
}
public class Upload extends JsonHttpRequest {
private static final String REST_PATH = "/2/upload.json"
private Upload(ImgurImage content) {
super(ImgurClient.this, HttpMethod.POST, REST_PATH, content);
}
public void execute() throws IOException {
executeUnparsed();
}
}
I recommend taking a look at our Drive API sample at http://samples.google-api-java-client.googlecode.com/hg/drive-cmdline-sample/instructions.html
Here's a code snippet:
private static final java.io.File UPLOAD_FILE = new java.io.File(UPLOAD_FILE_PATH);
/** Uploads a file using either resumable or direct media upload. */
private static File uploadFile(boolean useDirectUpload) throws IOException {
File fileMetadata = new File();
fileMetadata.setTitle(UPLOAD_FILE.getName());
InputStreamContent mediaContent = new InputStreamContent("image/jpeg", new BufferedInputStream(
new FileInputStream(UPLOAD_FILE)));
mediaContent.setLength(UPLOAD_FILE.length());
Drive.Files.Insert insert = drive.files().insert(fileMetadata, mediaContent);
MediaHttpUploader uploader = insert.getMediaHttpUploader();
uploader.setDirectUploadEnabled(useDirectUpload);
uploader.setProgressListener(new FileUploadProgressListener());
return insert.execute();
}
I use httpClient and I use FileBody to send a file to a server, as part of a MultiPartEntity. This works for Picasa, Flickr, etc.
it looks like you adopted a sample that was uploading text (json in content, json in the REST URL endpoint) and used it to attempt image upload ( upload(ImgurImage) ).
So, look at the source for the 'GenericJson.upload(ImgurImage)'...
See what this method does when it sets the 'content' field prior to calling 'exec' on the POST.
Understand that these frameworks will allow either strings and text in content or allow bitmaps ( bytes ) for images and audio type uploads.
Look for a handler that sets the 'content' and understand how it handles both bytes and strings for the json sample.
that should help you use the framework you have chosen.

Categories

Resources