Enable Push Notification for Android
HYPR SDK for Android: Web Authentication
Do This First
This process assumes that you have an existing Firebase project and that you have connected it to Control Center via Configuring Push Notifications via FireBase.
Follow these integration steps to facilitate out-of-band (OOB) Authentication with Firebase push notifications for your Android project.
- Open your Firebase console and select the project you wish to use.
- Click Project Overview on the left; then select the Android icon.

- Fill in the Android package name and App nickname; add a SHA sum if desired. When finished, click Register App.

- Download
google.services.json
to theapp/
directory and click Next.

- Follow the instructions to modify the
app/build.gradle
file, then click Next. HYPR includes this entry by default in the reference app.

- If you are satisfied with your project configuration, click Continue to console.

Add HYPR Dependencies
Copy the Android .aar
files into the app/libs
directory from the downloaded package /aars
folder. These will be referenced as needed in the modules' build.gradle
files.
Add Firebase SDK to Your Android App
Here is an example of the default shipped app/commonlibraries/build.gradle
file:
plugins {
id 'com.android.library'
id 'kotlin-android'
}
// HYPR Related
ext {
hyprVersion = "7.3.0"
hyprCode = 70300
cryptoVersion = "3.7.0"
adpVersion = "3.6.0"
}
android {
compileSdkVersion 31
buildToolsVersion "30.0.2"
defaultConfig {
targetSdkVersion 31
versionCode hyprCode
versionName hyprVersion
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
// HYPR Related
minSdkVersion 23 // Minimum Android API Version that the HYPR SDK supports
multiDexEnabled true // Gets past the 65,536 method limit that can be referenced in a single DEX file
ndk {
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
// Restricts the set of ABIs that the application supports.
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
// HYPR Related: References the HYPR AARs in the /libs directory
allprojects {
repositories {
jcenter()
flatDir {
dirs "$rootProject.projectDir/libs"
}
}
}
dependencies {
api fileTree(dir: "$rootProject.projectDir/libs", include: ['*.jar'])
// Android
api 'androidx.multidex:multidex:2.0.1'
api 'androidx.appcompat:appcompat:1.3.1' // do not change yet - https://stackoverflow.com/questions/69033022/message-error-resource-androidattr-lstar-not-found
api 'com.google.android.material:material:1.4.0'
api 'androidx.constraintlayout:constraintlayout:2.1.2'
api 'androidx.lifecycle:lifecycle-extensions:2.2.0'
annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.4.0'
api "androidx.security:security-crypto:1.0.0"
// GJON / POJO
api 'com.google.code.gson:gson:2.8.6'
api 'org.apache.commons:commons-lang3:3.5'
// RxAndroid
api group: 'io.reactivex.rxjava2', name: 'rxandroid', version: '2.1.1'
api group: 'io.reactivex.rxjava2', name: 'rxjava', version: '2.2.21'
api 'javax.annotation:jsr250-api:1.0'
// Retrofit
api 'com.squareup.retrofit2:retrofit:2.9.0'
api 'com.squareup.retrofit2:converter-gson:2.9.0'
api 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
api 'com.squareup.okhttp3:logging-interceptor:4.9.3'
// QR Scanner
api 'com.google.mlkit:barcode-scanning:17.0.0'
// Fingerprint
api 'androidx.biometric:biometric:1.1.0'
// HYPR Crypto
api(name: "crypto", version: "${cryptoVersion}", ext: 'aar') { transitive = true }
api(name: 'HyprCommon', version: "${hyprVersion}", ext: 'aar')
api(name: 'HyprBiometricPrompt', version: "${hyprVersion}", ext: 'aar')
api(name: 'HyprPin', version: "${hyprVersion}", ext: 'aar')
api(name: 'HyprSilent', version: "${hyprVersion}", ext: 'aar')
api(name: 'HyprPresence', version: "${hyprVersion}", ext: 'aar')
}
Create the CustomFirebaseMessagingService
Subclass
CustomFirebaseMessagingService
SubclassNOTE
The example subclass is named
CustomFirebaseMessagingService
for the purposes of demonstration.
public class CustomFirebaseMessagingService extends FirebaseMessagingService {
@Override
public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
Map<String, String> data = remoteMessage.getData();
HyprPushNotificationAdapter.getInstance()
.setOnNotificationPressedLaunchActivity(MainActivity.class)
.shouldSavePendingAuthenticationRequest(true)
.processRemoteMessage(this, remoteMessage.getData());
}
@Override
public void onNewToken(@NonNull String s) {
super.onNewToken(s);
HyprPushNotificationAdapter.getInstance().onNewPushChannelId(this, s);
}
}
Activity That Processes the Push Notification
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
HyprApp.getDbAdapter().onNewIntent(this, intent);
}
@Override
protected void onPause() {
super.onPause();
HyprPushNotificationAdapter.getInstance().unregisterBroadcastReceiver(this);
}
@Override
protected void onResume() {
super.onResume();
HyprPushNotificationAdapter.getInstance().registerBroadcastReceiver(this, new HyprActionCallbacks.HyprWebLoginCallback() {
@Override
public void onSuccess(@NonNull HyprActionCallbacks.WebLoginType webLoginType, @NonNull HyprStatusResult hyprStatusResult) {
// success
}
@Override
public void onFailure(@NonNull HyprActionCallbacks.WebLoginType webLoginType, @NonNull HyprStatusResult hyprStatusResult) {
// fail
}
});
handlePushIfAvailable();
}
public void handlePushIfAvailable() {
if(HyprApp.getDbAdapter().isPushPayloadAvailable(this)) {
HyprActions.getInstance().startPushNotificationIntent(this, new HyprActionCallbacks.HyprWebLoginCallback() {
@Override
public void onSuccess(@NonNull HyprActionCallbacks.WebLoginType webLoginType, @NonNull HyprStatusResult hyprStatusResult) {
toast("Success");
}
@Override
public void onFailure(@NonNull HyprActionCallbacks.WebLoginType webLoginType, @NonNull HyprStatusResult hyprStatusResult) {
toast("Success");
}
});
}
else if (HyprApp.getDbAdapter().isPendingAuthenticationAvailable(this)) {
HyprActions.getInstance().startPendingAuthentication(this, new HyprActionCallbacks.HyprWebLoginCallback() {
@Override
public void onSuccess(@NonNull HyprActionCallbacks.WebLoginType webLoginType, @NonNull HyprStatusResult hyprStatusResult) {
toast("Success");
}
@Override
public void onFailure(@NonNull HyprActionCallbacks.WebLoginType webLoginType, @NonNull HyprStatusResult hyprStatusResult) {
toast("Fail");
}
});
}
}
Firebase in AndroidManifest.xml
AndroidManifest.xml
Ensure the following values are present in the web account unlock manifest in app/webaccountunlock/src/main/res
. Make sure to replace <package.path.to>
with the correct path from your build.
<manifest>
// ...
<application>
...
<service android:name="<package.path.to>.CustomFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
...
</application>
</manifest>
Update the MultiDexApplication
Subclass
MultiDexApplication
Subclasspublic class App extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
initPushNotifications();
HyprApp.initializeApp(this, new HyprInit.InitTrustDataCallback() {
@Override
public void onInstallComplete() {
Log.d(LOG_TAG, "onInstallComplete");
updateWebAppProfile()
}
@Override
public void onInstallError(@NonNull String s, @Nullable Throwable throwable) {
Log.e(LOG_TAG, "onInstallError: " + s);
}
});
}
private void updateWebAppProfile() {
try {
HyprAppProfileData appProfileData = HyprApp.getDbAdapter().getCurHyprAppProfileData(this);
appProfileData.setCustomerConfiguredDefaultRpVersion(this, 4);
appProfileData.setHyprRpAppType(this, HyprRpAppType.WebsiteOnly);
} catch (HyprException e) {
Log.e(LOG_TAG, e.toString());
}
}
private void initPushNotifications() {
FirebaseApp.initializeApp(this);
HyprPushNotificationAdapter.getInstance().setPushId(context, FirebaseModel.getFirebaseSenderId());
}
}
UI Customization
We can customize the OOB Device Setup screens via XML overrides. Each screen has a corresponding XML layout file. By creating a layout file with the same name as the one you want to override, the SDK will present that layout file instead.
Android IDs
If you are overriding the layout files, please make sure to keep all the
android:ids
with their respective view from the layout that you want to override as the SDK uses those IDs.
Overriding the OOB Device Setup Screen
Create a file called hypr_common_view_single_pin.xml
using the example below. Now you can alter/add views and change the properties of those views.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/layout_movable_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/hypr_pin_layout_pin_one"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/layout_pin_instructions_text"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:orientation="horizontal">
<com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
android:id="@+id/hypr_pin_editview_pin_one_first"
style="@style/PinEditTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/hyprColorPinFocusedLine" />
<com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
android:id="@+id/hypr_pin_editview_pin_one_second"
style="@style/PinEditTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/hyprColorPinFocusedLine" />
<com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
android:id="@+id/hypr_pin_editview_pin_one_third"
style="@style/PinEditTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/hyprColorPinFocusedLine" />
<com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
android:id="@+id/hypr_pin_editview_pin_one_fourth"
style="@style/PinEditTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/hyprColorPinFocusedLine" />
<com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
android:id="@+id/hypr_pin_editview_pin_one_fifth"
style="@style/PinEditTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/hyprColorPinFocusedLine" />
<com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
android:id="@+id/hypr_pin_editview_pin_one_sixth"
style="@style/PinEditTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/hyprColorPinFocusedLine" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_pin_instructions_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/hypr_common_view_cancel_button"
android:layout_marginTop="@dimen/hypr_common_pin_instructions_text_margin_top"
android:layout_marginBottom="@dimen/hypr_common_pin_instructions_text_margin_bottom"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/sharetech_regular"
android:gravity="center_horizontal"
android:text="@string/hypr_pin_instructions_title"
android:textColor="@color/hyprColorTextPrimary"
android:textSize="@dimen/hypr_common_license_entry_title_size" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/sharetech_regular"
android:gravity="center_horizontal"
android:text="@string/hypr_pin_instructions_text"
android:textColor="@color/hyprColorTextPrimary"
android:textSize="@dimen/hypr_common_license_entry_desc_size" />
<com.hypr.hyprandroidcommon.uiadapter.ui.icons.SetupWorkstationAndDevice
android:layout_width="@dimen/hypr_common_license_entry_img_width"
android:layout_height="@dimen/hypr_common_license_entry_img_height"
android:layout_marginTop="@dimen/hypr_common_license_entry_img_margin_top"
android:contentDescription="@string/hypr_todo_content_description"
android:gravity="center_horizontal" />
</LinearLayout>
<include
android:id="@+id/hypr_common_view_cancel_button"
layout="@layout/hypr_common_view_cancel_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/view_pin_entry_text_buffer"
android:layout_marginBottom="@dimen/hypr_common_pin_cancel_margin_bottom" />
<View
android:id="@+id/view_pin_entry_text_buffer"
android:layout_width="match_parent"
android:layout_height="@dimen/hypr_common_pin_buffer_view_height"
android:layout_above="@+id/view_bottom_anchor"
android:visibility="visible" />
<View
android:id="@+id/view_bottom_anchor"
android:layout_width="match_parent"
android:layout_height="@dimen/hypr_common_keyboard_divider_bar_height"
android:layout_alignParentBottom="true"
android:background="@color/hyprColorKeyboardAnchorView"
android:visibility="invisible" />
</RelativeLayout>
<include layout="@layout/hypr_common_view_keyboard_layout" />
</RelativeLayout>

After OOB Device Setup is implemented, you can now perform OOB Authentication. For more information, please refer to the following documentation:
Out-of-band Authentication Setup: JavaScript Web SDK
Out-of-band Authentication Setup: Java Web SDK
Check the Server for Push Payload
In the event that the push notification does not arrive on the device, we still would like to authenticate.
The HYPR SDK for Android provides functionality to check the HYPR server for any push notifications for authentication, and if found, to start the authentication. You can do so with the code provided here:
val webAccounts = HyprApp.getDbAdapter().getCurHyprAppProfileData(activity).hyprMachineProfileDatas
val webAccount = webAccounts[0]; // Get the web account that you want to check
HyprActions.getInstance().checkServerForPendingAuthentication(activity, webAccount.dbId, object: HyprActionCallbacks.HyprActionCallback {
override fun onSuccess(statusResult: HyprStatusResult) {
HyprActions.getInstance().startPendingAuthentication(activity, object: HyprActionCallbacks.HyprWebLoginCallback {
override fun onSuccess(
webLoginType: HyprActionCallbacks.WebLoginType,
statusResult: HyprStatusResult
) {
}
override fun onFailure(
webLoginType: HyprActionCallbacks.WebLoginType,
statusResult: HyprStatusResult
) {
}
})
}
override fun onFailure(statusResult: HyprStatusResult) {
}
})
Updated 7 months ago