Commit 03624928 authored by Claudio Marforio's avatar Claudio Marforio
Browse files

Version 1.0.0

- Maven integration (and update to docs)
- Proguard rules sample
- Update sample app
- Update version of futuraekit.aar to 1.0.0
parent 85fa5584
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 28 compileSdkVersion 29
buildToolsVersion '28.0.3' buildToolsVersion '29.0.2'
defaultConfig { defaultConfig {
applicationId "com.futurae.futuraedemo" applicationId "com.futurae.futuraedemo"
...@@ -14,17 +14,28 @@ android { ...@@ -14,17 +14,28 @@ android {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug { debug {
minifyEnabled true
proguardFile 'proguard/futurae.pro'
proguardFile getDefaultProguardFile('proguard-android.txt')
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
productFlavors { }
repositories {
maven {
url "https://artifactory.futurae.com/artifactory/futurae-mobile"
credentials {
username = "anonymous"
password = ""
}
} }
} }
dependencies { dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support:appcompat-v7:28.0.0'
...@@ -37,12 +48,7 @@ dependencies { ...@@ -37,12 +48,7 @@ dependencies {
implementation 'com.google.firebase:firebase-core:16.0.7' implementation 'com.google.firebase:firebase-core:16.0.7'
implementation 'com.google.firebase:firebase-messaging:17.4.0' implementation 'com.google.firebase:firebase-messaging:17.4.0'
implementation 'com.squareup.retrofit2:retrofit:2.4.0' implementation('com.futurae.sdk:futuraekit:1.0.0')
implementation 'com.squareup.retrofit2:converter-moshi:2.4.0'
implementation 'com.squareup.moshi:moshi-adapters:1.6.0'
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
implementation(name:'futuraekit', ext:'aar')
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
-keep public enum com.futurae.sdk.model.Account$** {
**[] $VALUES;
public *;
}
-keep class com.futurae.sdk.DeviceInfo {
*;
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.futurae.futuraedemo"> package="com.futurae.futuraedemo">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera" />
...@@ -11,13 +12,13 @@ ...@@ -11,13 +12,13 @@
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:name="com.futurae.futuraedemo.AppMain" android:name="com.futurae.futuraedemo.AppMain"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<meta-data <meta-data
android:name="com.google.android.gms.vision.DEPENDENCIES" android:name="com.google.android.gms.vision.DEPENDENCIES"
...@@ -47,9 +48,9 @@ ...@@ -47,9 +48,9 @@
</activity> </activity>
<activity <activity
android:exported="false" android:exported="false"
android:name=".ui.FTRQRCodeActivity" android:name=".ui.FTRQRCodeActivity"
android:theme="@style/AppTheme" /> android:theme="@style/AppTheme" />
</application> </application>
</manifest> </manifest>
\ No newline at end of file
...@@ -2,6 +2,7 @@ package com.futurae.futuraedemo; ...@@ -2,6 +2,7 @@ package com.futurae.futuraedemo;
import android.app.Application; import android.app.Application;
import com.futurae.sdk.FuturaeClient; import com.futurae.sdk.FuturaeClient;
import com.futurae.sdk.Kit;
public class AppMain extends Application { public class AppMain extends Application {
...@@ -11,6 +12,6 @@ public class AppMain extends Application { ...@@ -11,6 +12,6 @@ public class AppMain extends Application {
super.onCreate(); super.onCreate();
FuturaeClient.launch(this, null); FuturaeClient.launch(this, (Kit)null);
} }
} }
...@@ -21,9 +21,12 @@ import android.util.Log; ...@@ -21,9 +21,12 @@ import android.util.Log;
import com.futurae.futuraedemo.R; import com.futurae.futuraedemo.R;
import com.futurae.sdk.FuturaeCallback; import com.futurae.sdk.FuturaeCallback;
import com.futurae.sdk.FuturaeClient; import com.futurae.sdk.FuturaeClient;
import com.futurae.sdk.FuturaeResultCallback;
import com.futurae.sdk.approve.ApproveSession; import com.futurae.sdk.approve.ApproveSession;
import com.futurae.sdk.model.Account; import com.futurae.sdk.model.Account;
import com.futurae.sdk.model.ApproveInfo;
import com.futurae.sdk.model.CurrentTotp; import com.futurae.sdk.model.CurrentTotp;
import com.futurae.sdk.model.SessionInfo;
import com.futurae.sdk.utils.NotificationUtils; import com.futurae.sdk.utils.NotificationUtils;
import com.google.android.gms.vision.barcode.Barcode; import com.google.android.gms.vision.barcode.Barcode;
...@@ -69,27 +72,46 @@ public class MainActivity extends AppCompatActivity { ...@@ -69,27 +72,46 @@ public class MainActivity extends AppCompatActivity {
// TODO: Handle URI call // TODO: Handle URI call
final String uriCall = getIntent().getDataString(); final String uriCall = getIntent().getDataString();
if (!TextUtils.isEmpty(uriCall)) { if (!TextUtils.isEmpty(uriCall)) {
FuturaeClient.sharedClient().handleUri(uriCall, new FuturaeCallback() {
@Override // Enrollment URI
public void success() { if (uriCall.contains("enroll")) {
Log.i(TAG, "success: URI handled"); FuturaeClient.sharedClient().handleUri(uriCall, new FuturaeCallback() {
@Override
// TODO: Handle enrollment and MobileAuth public void success() {
if (uriCall.contains("enroll")) { Log.i(TAG, "success: URI handled");
// URI Enrollment
showAlert("Success", "Successfully enrolled"); showAlert("Success", "Successfully enrolled");
} else {
// MobileAuth
finish();
} }
}
@Override @Override
public void failure(Throwable throwable) { public void failure(Throwable throwable) {
Log.e(TAG, "failure: failed to handle URI: " + throwable); Log.e(TAG, "failure: failed to handle URI: " + throwable);
showAlert("Error", "Could not handle URI call"); showAlert("Error", "Could not handle URI call");
} }
}); });
return;
}
// Auth URI
if (uriCall.contains("auth")) {
String userId = FuturaeClient.getUserIdFromUri(uriCall);
String sessionToken = FuturaeClient.getSessionTokenFromUri(uriCall);
FuturaeClient.sharedClient().sessionInfoByToken(userId, sessionToken,
new FuturaeResultCallback<SessionInfo>() {
@Override
public void success(SessionInfo sessionInfo) {
showApproveAlertDialog(new ApproveSession(sessionInfo), true);
}
@Override
public void failure(Throwable t) {
Log.e(TAG, "QR Code authentication failed: " + t.getLocalizedMessage());
}
});
return;
}
Log.e(TAG, "failure: failed to handle URI: " + uriCall);
showAlert("Error", "Could not handle URI call");
} }
} }
...@@ -145,7 +167,7 @@ public class MainActivity extends AppCompatActivity { ...@@ -145,7 +167,7 @@ public class MainActivity extends AppCompatActivity {
final Account account = accounts.get(0); final Account account = accounts.get(0);
CurrentTotp totp = FuturaeClient.sharedClient().nextTotp(account.getUserId()); CurrentTotp totp = FuturaeClient.sharedClient().nextTotp(account.getUserId());
showAlert("TOTP", "Code: " + totp.passcode + "\nRemaining seconds: " + totp.remainingSecs); showAlert("TOTP", "Code: " + totp.getPasscode() + "\nRemaining seconds: " + totp.getRemainingSecs());
} }
// QRCode callbacks // QRCode callbacks
...@@ -155,48 +177,55 @@ public class MainActivity extends AppCompatActivity { ...@@ -155,48 +177,55 @@ public class MainActivity extends AppCompatActivity {
Barcode qrcode = data.getParcelableExtra(FTRQRCodeActivity.PARAM_BARCODE); Barcode qrcode = data.getParcelableExtra(FTRQRCodeActivity.PARAM_BARCODE);
Log.i(TAG, "Scanned activation code from the QR code; will enroll device"); Log.i(TAG, "Scanned activation code from the QR code; will enroll device");
FuturaeClient.sharedClient().enroll(qrcode.rawValue, FuturaeClient.sharedClient().enroll(qrcode.rawValue,
new FuturaeCallback() { new FuturaeCallback() {
@Override @Override
public void success() { public void success() {
Log.i(TAG, "Enrollment successful"); Log.i(TAG, "Enrollment successful");
showAlert("Success", "Enrollment successful"); showAlert("Success", "Enrollment successful");
} }
@Override @Override
public void failure(Throwable throwable) { public void failure(Throwable throwable) {
Log.e(TAG, "Enrollment failed: " + throwable.getLocalizedMessage()); Log.e(TAG, "Enrollment failed: " + throwable.getLocalizedMessage());
showAlert("Error", "Enrollment failed"); showAlert("Error", "Enrollment failed");
} }
}); });
} }
private void onAuthQRCodeScanned(Intent data) { private void onAuthQRCodeScanned(Intent data) {
// TODO: Handle QRCode auth response
Barcode qrcode = data.getParcelableExtra(FTRQRCodeActivity.PARAM_BARCODE); Barcode qrcode = data.getParcelableExtra(FTRQRCodeActivity.PARAM_BARCODE);
Log.i(TAG, "Scanned authentication data from the QR code; will reply to server"); String userId = FuturaeClient.getUserIdFromQrcode(qrcode.rawValue);
FuturaeClient.sharedClient().approveAuth(qrcode.rawValue, String sessionToken = FuturaeClient.getSessionTokenFromQrcode(qrcode.rawValue);
new FuturaeCallback() {
@Override
public void success() {
Log.i(TAG, "QR Code authentication succeeded");
}
@Override FuturaeClient.sharedClient().sessionInfoByToken(userId, sessionToken,
public void failure(Throwable throwable) { new FuturaeResultCallback<SessionInfo>() {
Log.e(TAG, "QR Code authentication failed: " @Override
+ throwable.getLocalizedMessage()); public void success(SessionInfo sessionInfo) {
} showApproveAlertDialog(new ApproveSession(sessionInfo), false);
}); }
@Override
public void failure(Throwable t) {
Log.e(TAG, "QR Code authentication failed: " + t.getLocalizedMessage());
}
});
} }
// Approve dialog // Approve dialog
void showApproveAlertDialog(final ApproveSession session) { void showApproveAlertDialog(final ApproveSession session, final boolean isFromUri) {
// TODO: For demo purposes we simply show an alert instead of an approve screen // TODO: For demo purposes we simply show an alert instead of an approve screen
StringBuffer sb = new StringBuffer();
if (session.getInfo() != null) {
sb.append("\n");
for (ApproveInfo info : session.getInfo()) {
sb.append(info.getKey()).append(": ").append(info.getValue()).append("\n");
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Approve"); builder.setTitle("Approve");
builder.setMessage("Would you like to approve the request?"); builder.setMessage("Would you like to approve the request?" + sb.toString());
builder.setPositiveButton("Approve", new DialogInterface.OnClickListener() { builder.setPositiveButton("Approve", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
FuturaeClient.sharedClient().approveAuth(session.getUserId(), FuturaeClient.sharedClient().approveAuth(session.getUserId(),
...@@ -204,13 +233,16 @@ public class MainActivity extends AppCompatActivity { ...@@ -204,13 +233,16 @@ public class MainActivity extends AppCompatActivity {
@Override @Override
public void success() { public void success() {
Log.i(TAG, "Approve session allowed"); Log.i(TAG, "Approve session allowed");
if (isFromUri) {
finish();
}
} }
@Override @Override
public void failure(Throwable t) { public void failure(Throwable t) {
Log.e(TAG, "Failed to approve session: " + t.getLocalizedMessage()); Log.e(TAG, "Failed to approve session: " + t.getLocalizedMessage());
} }
}); }, session.getInfo());
} }
}); });
builder.setNegativeButton("Deny", new DialogInterface.OnClickListener() { builder.setNegativeButton("Deny", new DialogInterface.OnClickListener() {
...@@ -220,13 +252,16 @@ public class MainActivity extends AppCompatActivity { ...@@ -220,13 +252,16 @@ public class MainActivity extends AppCompatActivity {
@Override @Override
public void success() { public void success() {
Log.i(TAG, "Approve session rejected"); Log.i(TAG, "Approve session rejected");
if (isFromUri) {
finish();
}
} }
@Override @Override
public void failure(Throwable t) { public void failure(Throwable t) {
Log.e(TAG, "Failed to approve session: " + t.getLocalizedMessage()); Log.e(TAG, "Failed to approve session: " + t.getLocalizedMessage());
} }
}); }, session.getInfo());
} }
}); });
...@@ -303,17 +338,21 @@ public class MainActivity extends AppCompatActivity { ...@@ -303,17 +338,21 @@ public class MainActivity extends AppCompatActivity {
final ApproveSession session = intent.getParcelableExtra( final ApproveSession session = intent.getParcelableExtra(
NotificationUtils.PARAM_APPROVE_SESSION); NotificationUtils.PARAM_APPROVE_SESSION);
if (approveDialog != null && approveDialog.isShowing()) {
approveDialog.dismiss();
}
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
showApproveAlertDialog(session); showApproveAlertDialog(session, false);
} }
}); });
break; break;
case NotificationUtils.INTENT_APPROVE_CANCEL_MESSAGE: case NotificationUtils.INTENT_APPROVE_CANCEL_MESSAGE:
if (approveDialog != null && approveDialog.isShowing()) { if (approveDialog != null && approveDialog.isShowing()) {
approveDialog.dismiss(); approveDialog.dismiss();
} }
break; break;
......
...@@ -13,6 +13,6 @@ ...@@ -13,6 +13,6 @@
<!--ERRORS--> <!--ERRORS-->
<string name="error_low_storage">QR code scanning cannot be performed due to low device storage</string> <string name="error_low_storage">QR code scanning cannot be performed due to low device storage</string>
<string name="main_btn_logout">Logout</string> <string name="main_btn_logout">Logout</string>
</resources> </resources>
...@@ -5,7 +5,7 @@ buildscript { ...@@ -5,7 +5,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.3.2' classpath 'com.android.tools.build:gradle:4.0.0'
classpath 'com.google.gms:google-services:4.2.0' classpath 'com.google.gms:google-services:4.2.0'
} }
} }
...@@ -14,9 +14,6 @@ allprojects { ...@@ -14,9 +14,6 @@ allprojects {
repositories { repositories {
google() google()
jcenter() jcenter()
flatDir {
dirs 'src/main/libs'
}
} }
} }
......
#Fri Mar 15 11:07:02 CET 2019 #Wed Jul 22 17:41:42 CEST 2020
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
...@@ -5,11 +5,12 @@ This is the Android SDK of Futurae. You can read more about Futurae™ at [futur ...@@ -5,11 +5,12 @@ This is the Android SDK of Futurae. You can read more about Futurae™ at [futur
## Table of contents ## Table of contents
* [Basic integration](#basic-integration) * [Basic integration](#basic-integration)
* [Get FuturaeKit SDK for Android](#get-futuraekit-sdk-for-android) * [Get FuturaeKit SDK for Android via Maven](#get-futuraekit-sdk-for-android-via-maven)
* [Add SDK to Project](#add-sdk-to-project) * [Get FuturaeKit SDK for Android Manually](#get-futuraekit-sdk-for-android-manually)
* [Add permissions](#add-permissions) * [Add permissions](#add-permissions)
* [Basic setup](#basic-setup) * [Basic setup](#basic-setup)
* [Build your app](#build-your-app) * [Build your app](#build-your-app)
* [R8 / Proguard](#r8-proguard)
* [Features](#features) * [Features](#features)
* [Callbacks](#callbacks) * [Callbacks](#callbacks)
* [URI Schemes](#uri-schemes) * [URI Schemes](#uri-schemes)
...@@ -32,21 +33,43 @@ This is the Android SDK of Futurae. You can read more about Futurae™ at [futur ...@@ -32,21 +33,43 @@ This is the Android SDK of Futurae. You can read more about Futurae™ at [futur
## <a id="basic-integration" />Basic integration ## <a id="basic-integration" />Basic integration
We will describe the steps to integrate the FuturaeKit SDK into your Android project. We are going to assume that you are using Android Studio for your development. We will describe the steps to integrate the FuturaeKit SDK into your Android project. We are going to assume that you are using Android Studio for your development.
### <a id="get-futuraekit-sdk-for-android" />Get FuturaeKit SDK for Android ### <a id="get-futuraekit-sdk-for-android-via-maven" />Get FuturaeKit SDK for Android via Maven
You can download the latest SDK from the [releases](https://git.futurae.com/futurae-public/futurae-android-sdk/tags), or clone this repository directly. The *preferred* way to get the FuturaeKit SDK fro Android is through maven and the Futurae private repository.
This repository also contains a simple demo app to show how the SDK can be integrated.
To do so add the following lines to your `build.gradle` file:
```
repositories {
maven {
url "https://artifactory.futurae.com/artifactory/futurae-mobile"
credentials {
username = "anonymous"
password = ""
}
}
}
dependencies {
implementation('com.futurae.sdk:futuraekit:1.0.0')
}
```
Of course, make sure to specify the correct version number.
### <a id="get-futuraekit-sdk-for-android-via-maven" />Get FuturaeKit SDK for Android Manually
Alternatively, *although discouraged*, you can download the latest SDK from the [releases](https://git.futurae.com/futurae-public/futurae-android-sdk/tags), or clone this repository directly.
This repository also contains a simple demo app to show how the SDK can be integrated.
### <a id="add-sdk-to-project" />Add SDK to Project
To integrate the FuturaeKit SDK into your project, copy `futuraekit.aar` into the `src/main/libs` folder of your app. To integrate the FuturaeKit SDK into your project, copy `futuraekit.aar` into the `src/main/libs` folder of your app.
Then, in your modules `build.gradle` (the one under "app"), add the following dependencies: Then, in your modules `build.gradle` (the one under "app"), add the following dependencies:
``` ```
compile 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-moshi:2.3.0' implementation 'com.squareup.retrofit2:converter-moshi:2.3.0'
compile 'com.squareup.moshi:moshi-adapters:1.4.0' implementation 'com.squareup.moshi:moshi-adapters:1.4.0'
implementation 'com.squareup.okhttp3:okhttp:3.8.0' implementation 'com.squareup.okhttp3:okhttp:3.8.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.8.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'
compile(name:'futuraekit', ext:'aar') implementation 'com.github.nisrulz:easydeviceinfo-base:2.4.1'
implementation files('src/main/libs/futuraekit.aar')
``` ```
![][gradle-app] ![][gradle-app]
...@@ -124,6 +147,12 @@ Secondly, in your `res/values` folder make sure to create a file `futurae.xml` w ...@@ -124,6 +147,12 @@ Secondly, in your `res/values` folder make sure to create a file `futurae.xml` w
Build and run your app. If the build succeeds, you should carefully read the SDK logs in the console.