Quickstart: Android WebView
Below are some code snippets to get you integrating with the WebView API as soon as possible.
Demo App
If you just want to kick the tires on the WebView, we have an open source example app available at persona-id/persona-android-webview that you can clone and open in Android Studio.
# If you want to build and install the demo app from the command line:
git clone https://github.com/persona-id/persona-android-webview
cd persona-android-webview
./gradlew installDebug
Example Code
To launch the WebView, create a WebView
and pass in query parameters specified in WebView Flow.
// inside Activity#onCreate
// assuming some WebView called "webView"
WebSettings settings = webView.getSettings();
settings.setDomStorageEnabled(true);
settings.setJavaScriptEnabled(true);
settings.setMediaPlaybackRequiresUserGesture(false);
final Uri personaUrl = new Uri.Builder()
.scheme("https")
.encodedAuthority("withpersona.com")
.path("verify")
.appendQueryParameter("is-webview", "true")
.appendQueryParameter("template-id", "tmpl_JAZjHuAT738Q63BdgCuEJQre")
.appendQueryParameter("environment", "sandbox")
// optional - specify theme for new inquiry
// .appendQueryParameter("theme-id", "the_Z7S2Ltor9fp2oEGXMLXBPsHa")
.build();
webView.loadUrl(personaUrl.toString());
Handling Permissions
Be sure to add the required permissions for your use case to your AndroidManifest file. For example:
<uses-permission android:name="android.permission.CAMERA" />
See https://github.com/persona-id/persona-android-webview/blob/main/app/src/main/AndroidManifest.xml in our sample app.
In addition to adding to the Manifest file, you'll need to override onPermissionRequest and onShowFileChooser depending on your use case. See an example below.
// set fields on your Activity
public static final int INPUT_FILE_REQUEST_CODE = 1;
private static final int CAMERA_PERMISSION_REQUEST = 1111;
private PermissionRequest cameraPermission;
private ValueCallback<Uri[]> filePathCallback;
private String cameraPhotoPath;
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != INPUT_FILE_REQUEST_CODE || filePathCallback == null) {
super.onActivityResult(requestCode, resultCode, data);
return;
}
Uri[] results = null;
// Check that the response is a good one
if (resultCode == Activity.RESULT_OK) {
if (data == null) {
// If there is not data, then we may have taken a photo
if (cameraPhotoPath != null) {
results = new Uri[] { Uri.parse(cameraPhotoPath) };
}
} else {
String dataString = data.getDataString();
if (dataString != null) {
results = new Uri[] { Uri.parse(dataString) };
}
}
}
filePathCallback.onReceiveValue(results);
filePathCallback = null;
}
// in the Activity#onCreate method
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onPermissionRequest(final PermissionRequest request) {
if (request.getOrigin().toString().equals("https://withpersona.com/")) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[] { Manifest.permission.CAMERA }, CAMERA_PERMISSION_REQUEST);
cameraPermission = request;
} else {
request.deny();
}
}
@Override
public boolean onShowFileChooser(
WebView webView, ValueCallback<Uri[]> newFilePathCallback,
FileChooserParams fileChooserParams) {
if (filePathCallback != null) {
filePathCallback.onReceiveValue(null);
}
filePathCallback = newFilePathCallback;
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
try {
photoFile = File.createTempFile(imageFileName, ".jpg", storageDir);
} catch (IOException ex) {
// Error occurred while creating the File
}
// Continue only if the File was successfully created
if (photoFile != null) {
cameraPhotoPath = "file:" + photoFile.getAbsolutePath();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
} else {
takePictureIntent = null;
}
}
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
contentSelectionIntent.setType("image/*");
Intent[] intentArray;
if (takePictureIntent != null) {
intentArray = new Intent[] { takePictureIntent };
} else {
intentArray = new Intent[0];
}
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);
return true;
}
});
// overwriting your AppCompatActivity's #onRequestPermissionsResult
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_PERMISSION_REQUEST) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
cameraPermission.grant(cameraPermission.getResources());
} else {
cameraPermission.deny();
}
}
}
Handling the callback redirect
On a successful or canceled inquiry flow, Persona will redirect to the redirectUri specified on when launching the flow, or "personacallback" if no custom redirectUri is specified. You can retrieve the query parameters specified in WebView Flow on the redirectUri.
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Uri parsedUri = Uri.parse(url);
if (Objects.equals(parsedUri.getAuthority(), "personacallback")) {
// User succeeded verification or `inquiryID` is `null`
String inquiryId = parsedUri.getQueryParameter("inquiry-id");
// ... do something with the inquiryId
return true;
} else {
return false;
}
}
Updated 4 months ago