Jeet.Deir Jeet.Deir - 2 months ago 18
Java Question

java.net.URL.getFile() on a null object reference

So I need to pass a key (

.p12
) file
SERVICE_ACCT_KEYFILE
which is stored directly under the
res
folder in my Android project. I am setting the
setServiceAccountPrivateKeyFromP12File()
as this:

private static GoogleCredential authorize() throws Exception {
return new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCT_EMAIL)
.setServiceAccountPrivateKeyFromP12File(new File(
PredictionSample.class.getResource("/" + SERVICE_ACCT_KEYFILE).getFile()))
.setServiceAccountScopes(Arrays.asList(PredictionScopes.PREDICTION,
StorageScopes.DEVSTORAGE_READ_ONLY))
.build();
}


This example works perfectly in Java and yet when I am trying to implement it in Android and I have the following error:

Attempt to invoke virtual method 'java.lang.String java.net.URL.getFile()' on a null object reference


Even doing this it fails:

String keyPath = "android.resource://" + MainActivity.PACKAGE_NAME + "/" + R.raw.pretense307cf970d6b1;

return new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCT_EMAIL)
.setServiceAccountPrivateKeyFromP12File(new File(
PredictionSample.class.getResource(keyPath).getFile()))
.setServiceAccountScopes(Arrays.asList(PredictionScopes.PREDICTION,
StorageScopes.DEVSTORAGE_READ_ONLY))
.build();
}


How do I resolve the same?

Thanks.

Answer

In order to access a resource in an Android application, it should be located either in src/main/res/raw or src/main/assets directory. Android doesn't load resources via classloader.

If the p12 file, say, keyfile.p12 is in src/main/res/raw directory, it can be accessed this way:

InputStream rawIs = getResources().openRawResource(R.raw.keyfile);

If keyfile.p12 is in src/main/assets directory:

InputStream assetIs = getAssets().open("keyfile.p12");

Then you'll need to save the InputStream into a File. You can create a file inside your app internal storage with new File(getFilesDir(), "keyfile.p12") or any method available in Context class that returns a directory for file storage instead of getFilesDir(). I leave the file copying code as an exercise :)

All of getResources(), getAssets() and getFilesDir() are instance methods of Context class.

Some reference, and explanation of the difference between raw and assets: https://developer.android.com/guide/topics/resources/providing-resources.html