Upload photos from Android app to Google Cloud Storage/App Engine - illegal character '_'

android, google-app-engine, google-cloud-storage, java

Solution

Resolved!

I had 2 problems.

I was encoding the string improperly. When I actually looked at the outputted JSON, I could see the there were "_" in the string. I fixed this by using adding the line

String s = Base64.encodeToString(b, Base64.DEFAULT);

I had tried that before but the image still wouldn't display properly.

I wasn't wrapping the byte array in a ByteBuffer, before uploading to GCS:

GcsOutputChannel outputChannel = gcsService.createOrReplace(name, optionsBuilder.build()); outputChannel.write(ByteBuffer.wrap(bytes)); outputChannel.close();

Problem

I've having trouble uploading photos from my android app to GCS. I'm able to upload text files but not photos. I've tried various mime-types as well as different Base64 encoding methods (decodeBase64, encodeBase64URLSafeString, etc...) I feel like I'm really close. This is the error message that I receive: com.google.appengine.repackaged.org.codehaus.jackson.JsonParseException: Illegal character '_' (code 0x5f) in base64 content at [Source: N/A; line: -1, column: -1] I looked at the encoded String and there aren't any '_' in there. Android code: ``` Activity: protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case 0: { try { InputStream is = getContentResolver().openInputStream(data.getData()); tvMessage.setText("Done!"); byte[] b = getBytes(is); gaeTask task = new gaeTask(); PhotoObject p = new PhotoObject(); p.encodeBytes(b); p.setName("picturejpg.jpg"); task.execute(p); } } AsnycTask: protected String doInBackground(PhotoObject... params) { String responseMessage = ""; try { PhotoObjectEndpoint builder = new PhotoObjectEndpoint(AndroidHttp.newCompatibleTransport(), new JacksonFactory(), new HttpRequestInitializer() { @Override public void initialize(HttpRequest arg0) throws IOException { // TODO Auto-generated method stub } }); PhotoObject p = params[0]; builder.insertPhotoObject(p).execute(); responseMessage = p.getName() + " was successfully deployed."; } ``` GAE/GCS Code: ``` GAE – PhotoObject: @Entity public class PhotoObject { public PhotoObject(){} @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Key key; public Key getKey() { return key; } public void setKey(Key key) { this.key = key; } private String mBytes; public byte[] getBytes() { return decodeBytes(); } public void setBytes(byte[] mBytes) { this.mBytes = encodeBytes(mBytes); } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } private FileType type; public FileType getType() { return type; } public void setType(FileType type) { this.type = type; } /** * * @see #getBytes() * @return Base64 decoded value or {@code null} for none * * @since 1.14 */ public byte[] decodeBytes() { return com.google.api.client.util.Base64.decodeBase64(mBytes); } /** * * @see #setBytes() * * <p> * The value is encoded Base64 or {@code null} for none. * </p> * * @since 1.14 */ public String encodeBytes(byte[] bytes) { //this.mBytes = com.google.api.client.util.Base64.encodeBase64URLSafeString(bytes); this.mBytes = com.google.api.client.util.Base64.encodeBase64String(bytes); return this.mBytes; } } GAE - insertPhotoObject: try { final GcsService gcsService = GcsServiceFactory.createGcsService(RetryParams.getDefaultInstance()); GcsFilename name = new GcsFilename("testbucket123", fileName); GcsFileOptions.Builder optionsBuilder = new GcsFileOptions.Builder(); optionsBuilder.mimeType("image/jpg"); GcsOutputChannel outputChannel = gcsService.createOrReplace(name, optionsBuilder.build()); ObjectOutputStream out = new ObjectOutputStream(Channels.newOutputStream(outputChannel)); out.write(bytes); out.close(); } ``` Thanks in advance.

Original source