Android Setup
Learn how to implement Lens in an Android application
Getting Started
Lens is a camera framework that captures C2PA-compliant verified photos and videos. After successful capture, photos contain assertions (such as location, date and time, used to verify the provenance of the image), and are
cryptographically signed.
Requirements
- Lens Android API key. Truepic requires the following information for production keys:
- App name - The name of the application as listed in the Play Store.
- Package name - The name of the package as it will be submitted to the Google Play Store.
- Certificate digest - A short and unique representation of a certificate used to digitally sign your APK before it is installed on a device or updated. Please convert the hexadecimal fingerprint to base64 before sharing with us. See Certificate Digests to learn more.
- Recommended Android 13, API level 33
- Minimum of Android 9, API level 28 1.7.3+
- Gradle 7.4.2+
Basic installation
- Validate the SHA256 release checksum
Before using the Lens SDK, make sure that its SHA256 checksum is correct.
For MacOS, runshasum -c checksum_release.txt
.
The result should beLensSdk-release-X.X.X.X.zip: OK
- Import the library
Extract files from the LensSDK zip into a folder inside your Android project, for examplelibs/lens
.
The SDK comes with a built-inconsumers-rules.pro
file that contains all the necessary rules for the Proguard to work correctly.
Integration
Gradle setup
- Specify your folder as repository in your project
build.gradle
:
allprojects {
repositories {
// LensSDK
maven {
url rootProject.file("libs/lens")
}
// other repositories
google()
mavenCentral()
}
}
- Then you can use LensSDK as any other dependency in your module
build.gradle
:
implementation 'com.truepic:lens:X.X.X.X'
- Add the following Lens dependency to your
gradle.properties
. Missing this line will cause this build error:Unsupported class file major version 59
.
android.jetifier.ignorelist = bcprov-jdk18on
Manifest configuration
These steps are all required for your camera to work properly.
- Request Android permissions. Before opening a camera, the following permissions need to be defined in the project’s manifest file:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- Check permissions. Then, request and check for permissions at runtime. The camera view will not work without these and the
LensError
object will be raised with additional details.
Manifest.permission.CAMERA,
Manifest.permission.ACCESS_FINE_LOCATION
- Set application parameters. The application elements in the manifest need to include the following parameters in order for the
SecuredSharedPreferences
and timestamping to work correctly.
<application
...
android:allowBackup="false"
android:fullBackupContent="false"
android:usesCleartextTraffic="true" />
- Set attributes. Attribute tags must be declared in the manifest file.
<activity
...
android:exported="true">
Play Integrity configuration
Note
This section only applies to production apps distributed via the Google Play store.
Lens uses the Google Play Integrity API. This works out of the box with no configuration required for development apps, or production apps not distributed via the Google Play store. For apps in the Google Play store, Google requires a few additional steps, easily configurable in the Play Console. If not configured properly, the store will alert you.
- In the Play Console, navigate to the Release section of the left menu.
- Go to Setup > App Integrity and select the API tab.
- Choose an existing project or create a new project from the Google Cloud Console.
- Go to APIs and services and select enable APIs and services.
- Search for Play Integrity API. Select it and then select Enable.
Please allow about 30 minutes for the change to take effect.
React Native notes
If you're encountering difficulties integrating Lens into a React Native module inside a view, call setupLayoutHack()
.
fun setupLayoutHack() {
Choreographer.getInstance().postFrameCallback(object : Choreographer.FrameCallback {
override fun doFrame(frameTimeNanos: Long) {
manuallyLayoutChildren()
viewTreeObserver.dispatchOnGlobalLayout()
Choreographer.getInstance().postFrameCallback(this)
}
})
}
fun manuallyLayoutChildren() {
for (i in 0 until childCount) {
val child = getChildAt(i)
child.measure(MeasureSpec.makeMeasureSpec(measuredWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY))
child.layout(0, 0, child.measuredWidth, child.measuredHeight)
}
}
Implementation
Set up camera preview
LensCameraView
is provided to facilitate camera preview:
<com.truepic.lenssdk.LensCameraView
android:id="@+id/lensCameraView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Add your API key
Warning
API keys should not be stored in plain text. We recommend you store it obfuscated using NDK. See the secrets gradle plugin or read this Medium article for additional advice.
Once LensCameraView
is present in one of the layouts, set up a valid API key and listeners for it. This could be done in an activity’s onCreate
or fragment’s onCreateView
methods (depending on where the view from above is being used).
lensCameraView.setApiKey("api key here", object : LensHandler {
override fun onError(error: LensError) {
// handle errors here
}
override fun enableCapture(cameraEnabled: Boolean) {
// use cameraEnabled boolean
}
}, useStrongbox)
lensCameraView.setApiKey("api key here", new LensHandler() {
@Override
public void onError(LensError lensError) {
// handle errors here
}
@Override
public void enableCapture(boolean cameraEnabled) {
// use cameraEnabled boolean
}
}, useStrongbox);
- We recommend you enable camera capture only when
cameraEnabled
istrue
. If there’s any error that would prevent the camera from working, the app will be notified using theLensError
object that contains the message and type of the error. useStrongbox
- Boolean - Enable or Disable hardware security StrongBox for supported devices.
Capture a photo
In order to initiate secure capture, the application needs to call the startPhotoCapture
method of the LensCamera
interface. First, we'll call onThumbnailCaptured
, which contains a low resolution image that could be used as a preview. This image does not contain image provenance. Then, onTruepicCaptured
will return the C2PA signed image. UUID could be used to update or remove previously created low resolution thumbnails.
lensCamera.startPhotoCapture(object : LensPhotoCaptureHandler {
override fun onTruepicCaptured(uuid: UUID, truepic: Truepic) {
// truepic captured
}
override fun onThumbnailCaptured(uuid: UUID, truepic: Truepic) {
// thumbnail captured
}
override fun onBlurScoreCalculated(uuid: UUID, blurScore: float) {
// Evaluate blur score (or ignore it)
}
})
lensCamera.startPhotoCapture(new LensPhotoCaptureHandler() {
@Override
public void onTruepicCaptured(UUID uuid, Truepic truepic) {
// truepic captured
}
@Override
public void onThumbnailCaptured(UUID uuid, Truepic truepic) {
// thumbnail captured
}
@Override
public void onBlurScoreCalculated(UUID uuid, float blurScore) {
// Evaluate blur score (or ignore it)
}
});
Capture a video
Lens API file size restriction
There are no restrictions on file size or duration to record verified videos and upload them to your own server. However, the Lens API restricts uploads to 100 MB per file. If you use the Lens API for video verification and processing, we recommend limiting recording to under 45 seconds per video.
To capture a video, the SDK will need to switch capture modes from LensCaptureMode.Photo
to LensCaptureMode.Video
using LensCamera.setCaptureMode(LensCaptureMode lensCaptureMode)
. After switching the capture mode, your application will need to call LensCamera.startRecordingVideo
to start recording by providing it a LensVideoCaptureHandler
.
Once recording has started you must call LensCamera.stopRecordingVideo()
to stop recording. Please note that it is possible to encounter an error, which stops recording prematurely. Be sure to check for any errors if LensVideoCaptureHandler.onRecordingFinished()
is raised without explicitly telling the SDK to stop the recording.
lensCamera.startRecordingVideo(object : LensVideoCaptureHandler {
override fun onTruepicVideoCaptured(uuid: UUID, truepicVideo: TruepicVideo?) {
// This is called when recording has finished.
}
override fun onThumbnailCaptured(uuid: UUID, thumbnailAsJpeg: ByteArray) {
// This is called when a video thumbnail has been generated. The thumbnail is stored as a JPEG in the byte array.
}
override fun onRecordingStarted() {
// This is called when recording has started.
}
override fun onUpdate(recordedDurationNanos: Long) {
// While recording this is called periodically, use this to update your duration timer. If your user experience
// does not include a duration timer this method can be left empty.
}
override fun onRecordingFinished() {
// This is called when recording has finished. If the recording finished prematurely please check for any recent
// errors.
}
})
lensCamera.startRecordingVideo(new LensVideoCaptureHandler() {
@Override
public void onTruepicVideoCaptured(UUID uuid, @Nullable TruepicVideo truepicVideo) {
// This is called when recording has finished.
}
@Override
public void onThumbnailCaptured(UUID uuid, byte[] thumbnailAsJpeg) {
// This is called when a video thumbnail has been generated. The thumbnail is stored as a JPEG in the byte array.
}
@Override
public void onRecordingStarted() {
// This is called when recording has started.
}
@Override
public void onUpdate(long recordedDurationNanos) {
// While recording this is called periodically, use this to update your duration timer. If your user experience
// does not include a duration timer this method can be left empty.
}
@Override
public void onRecordingFinished() {
// This is called when recording has finished. If the recording finished prematurely please check for any recent
// errors.
}
});
Capture an audio
In order to initiate secure audio capture, the application needs to call the startRecordingAudio
method of the LensAudio
interface. onTruepicAudioCaptured
will return the C2PA signed audio.
lensCamera.startRecordingAudio(object : LensAudioCaptureHandler {
override fun onTruepicAudioCaptured(uuid: UUID, truepicAudio: TruepicAudio) {
// truepicAudio captured
}
override fun onAudioRecordingStarted() {
// audio recording started
}
override fun onAudioRecordingFinished() {
// audio recording finished
}
})
lensCamera.startRecordingAudio(new LensAudioCaptureHandler() {
@Override
public void onTruepicAudioCaptured(UUID uuid, TruepicAudio truepicAudio) {
// truepicAudio captured
}
@Override
public void onAudioRecordingStarted() {
// audio recording started
}
@Override
public void onAudioRecordingFinished() {
// audio recording finished
}
});
Error Handling
The LensError
object is provided whenever an error occurs while initializing and working with the camera. Each error contains three values: message, error type, and exception (optional).
Error Type | Description |
---|---|
Permissions_Camera | Check permissions for accessing the camera |
Permissions_Location | Check location permissions |
Permissions_Microphone | Error was encountered while accessing microphone permission |
Env_AirplaneMode | Airplane mode is enabled and no internet connection is available |
Env_DevMode | Development mode or USB debugging is enabled |
Env_Network | No internet connection is available |
Env_Rooted | Device is rooted, which is not allowed for controlled capture |
Env_PlayStoreServices | Out of date or no play store services available on the device |
Env_Location | Location services are not available/enabled |
Env_Location_Not_Ready | Temporary error while the device is determining current location |
Env_Location_Not_Accurate | The location accuracy does not meet thresholds |
Env_Not_Expected_Location | Current device location is outside of expected location (geofencing) |
Env_Storage_Space | Not enough storage space for video recording available |
Camera | Errors associated with using the camera |
CaptureImageError CaptureVideoError | An error has occurred while signing the image/video |
RecordingVideo | An error has occurred while recording a video |
Attestation ShortValidityAttestation LongValidityAttestation | Device integrity is compromised, more details are provided within the message |
Enrollment | Device enrollment errors |
KeyGeneration | Errors occurring while working and generating cryptographic keys |
StrongBoxError | Non-blocking error when strongbox is unavailable on the device |
Native | Errors associated with native code |
Undefined | All other errors that might occur, please check associated message/exception |
Audio | General audio error |
Submitting your apps
Before submitting your production app to the App Store, please be sure to check that you are using:
- A separate Lens API key from your development app, for security. If you don't have one, please reach out to Truepic with your package name and SHA-256 fingerprint. The fingerprint may be different from your development app.
- The production flavor binary. For your convenience, we include a debug flavor, but this is not suitable for your production app.
- Play integrity is configured, see the section above.
Troubleshooting
Device is rooted error during development
If you're using an emulator like Android Studio, the good news is that it is not expected for you to be able to successfully capture or sign an image, due to our security measures that prevent this. A real, physical device must always be used.
In the standard release
version of the SDK, the Android device must neither be rooted nor in developer mode. To test an app with the release
version:
- Enable developer mode on the device
- Enable USB debugging
- Connect the device to Android Studio
- Deploy your app to the device
- Disable USB debugging on your device
- Disable developer mode on the device
- Run the app with the camera flow
During development, you can use the debugrelease
version of the SDK. This version allows you to skip the above steps and leave your physical device connected to your computer and still follow logs coming from the device.
Updated 3 months ago