Documentation on how to use FIA Android SDK.
Add the dependency in your app-level build.gradle (project/app/build.gradle)
dependencies {
// Another dependencies...
implementation 'com.fazpass:fia:1.1.8'
}Then sync project with gradle files.
Before using this SDK, make sure to get the Merchant Key and Merchant App ID from Keypaz Dashboard. Check this Dashboard Documentation.
Miscall needs these two permissions:
- Manifest.permission.READ_PHONE_STATE
- Manifest.permission.READ_CALL_LOG
Add these lines in your android manifest file:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />Then request for runtime permissions like this:
Kotlin
val requiredPermissions = arrayOf(Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_CALL_LOG)
ActivityCompat.requestPermissions(this, requiredPermissions, 0)Java
String[] requiredPermissions = { Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_CALL_LOG };
ActivityCompat.requestPermissions(this, requiredPermissions, 0);Add this line in your android manifest file, in the application tag:
android:networkSecurityConfig="@xml/fia_network_security_rules"<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/fia_network_security_rules">
<!-- Your declared activity tags, service tags etc. -->
</application>Already had a network security config rules in your app?
Then this is the configuration needed for FIA:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- other domain configurations... -->
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">verify.klikaman.online</domain>
<domain includeSubdomains="true">api.fazpass.com</domain>
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</domain-config>
</network-security-config>Add this code in your android manifest file, inside the application tag:
<activity
android:name="com.fazpass.fia.activities.magiclink.MagicLinkActivity"
android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="YOUR_DOMAIN"
android:scheme="https" />
</intent-filter>
</activity>Fill YOUR_DOMAIN with your website domain.
Then create a new file named assetlinks.json with this content:
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "YOUR_PACKAGE_NAME",
"sha256_cert_fingerprints": ["YOUR_SHA256_CERT_FINGERPRINT"]
}
}
]Fill YOUR_PACKAGE_NAME with your app package name (example: com.example.app),
YOUR_SHA256_CERT_FINGERPRINT with your app SHA256 certificate fingerprint.
In assetlinks.json, sha256_cert_fingerprints is an array. You can add more than one certificate fingerprints in here.
- Follow this Android App Signing Documentation up until you created a keystore
- Run this command in your console to check your keystore (.jks or .keystore) information:
keytool -list -v -keystore MY_KEYSTORE.jks - Enter your keystore password
- Console will print out your keystore information. Copy the SHA256 certificate fingerprints value
- Add the certificate fingerprint to the sha256_cert_fingerprints array
- After you uploaded your app to Playstore, open Google Play Console
- Navigate to your app > Test & Release > App Integrity > App Signing
- Copy the SHA256 certificate fingerprints value
- If the value is different from the first one, add the certificate fingerprint to the sha256_cert_fingerprints array
Then save the assetlinks.json file and serve it in your domain with this link: https://YOUR_DOMAIN.com/.well-known/assetlinks.json. Make sure:
- It's available for public access
- No Redirect
- Content-Type is application/json
First, you have to initialize the sdk once.
Kotlin
import com.fazpass.fia.FIAFactory
// get fia instance
val fia = FIAFactory.getInstance()
fia.initialize(this, "YOUR_MERCHANT_KEY", "YOUR_MERCHANT_APP_ID")Java
import com.fazpass.fia.FIAFactory;
import com.fazpass.fia.interfaces.FIA;
// get fia instance
FIA fia = FIAFactory.getInstance();
fia.initialize(this, "YOUR_MERCHANT_KEY", "YOUR_MERCHANT_APP_ID");There are two ways to request an OTP:
- With premade activity
If you want to request an OTP without making any view/UI for the OTP activity. - With custom-made activity
If you want to make your own view/UI for the OTP activity.
Requesting an OTP with premade activity is easier than requesting an OTP with custom-made activity. Use this one if you don't want to make your own view/UI.
Then assign this variable in the activity onCreate() method with fia.otpActivity(this).
Kotlin
import com.fazpass.fia.FIAFactory
import com.fazpass.fia.objects.OtpActivitySettings
class MainActivity: AppCompatActivity() {
private val fia = FIAFactory.getInstance()
// class-level variable
private lateinit var otp: OtpActivitySettings
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// If FIA has not been initialized once, uncomment the line below.
// fia.initialize(this, "YOUR_MERCHANT_KEY", "YOUR_MERCHANT_APP_ID")
otp = fia.otpActivity(this)
}
}Java
import com.fazpass.fia.FIAFactory;
import com.fazpass.fia.interfaces.FIA;
import com.fazpass.fia.objects.OtpActivitySettings;
public class MainActivity extends AppCompatActivity {
private final FIA fia = FIAFactory.getInstance();
// class-level variable
private OtpActivitySettings otp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// If FIA has not been initialized once, uncomment the line below.
// fia.initialize(this, "YOUR_MERCHANT_KEY", "YOUR_MERCHANT_APP_ID");
otp = fia.otpActivity(this);
}
}To launch the OTP activity, call one of the four methods which fits the purpose of the otp:
- login()
- register()
- transaction()
- forgetPassword()
For example, we will use the login method.
Kotlin
otp.login("PHONE_NUMBER") { transactionId: String? ->
// If transactionId is null, OTP validation has an error.
if (transactionId == null) {
// handle failed OTP validation here...
return@login
}
// with the transactionId, check for the user verified status here...
}Java
otp.login("PHONE_NUMBER", transactionId -> {
// If transactionId is null, OTP validation has an error.
if (transactionId == null) {
// handle failed OTP validation here...
return null;
}
// with the transactionId, check for the user verified status here...
return null;
});Get the transactionId, then check the segment down below on how to check if user has been successfully verified.
Unlike requesting OTP with premade activity, you don't have to assign the variable in the activity onCreate() method. Also, there are more steps involved.
Kotlin
import com.fazpass.fia.objects.OtpPromise
class Constants {
companion object {
lateinit var otpPromise: OtpPromise
}
}Java
import com.fazpass.fia.objects.OtpPromise;
public class Constants {
public static OtpPromise otpPromise;
}To request for an OTP, call one of the four methods which fits the purpose of the otp:
- login()
- register()
- transaction()
- forgetPassword()
For example, we will use the register method.
Kotlin
fia.otp(this).register("PHONE_NUMBER") { promise ->
if (promise.hasException) {
val exception = promise.exception
// handle failed OTP request here...
return@register
}
Constants.otpPromise = promise
}Java
fia.otp(this).register("PHONE_NUMBER", promise -> {
if (promise.getHasException()) {
Exception exception = promise.getException();
// handle failed OTP request here...
return null;
}
Constants.otpPromise = promise;
return null;
})Here, you can launch between activities according to their authentication type as described in the example below.
Kotlin
import com.fazpass.fia.objects.OtpAuthType
when (Constants.otpPromise.authType) {
OtpAuthType.HE -> {
val intent = Intent(this@MainActivity, ValidateHEActivity::class.java)
startActivity(intent)
}
OtpAuthType.Miscall -> {
val intent = Intent(this@MainActivity, ValidateMiscallActivity::class.java)
startActivity(intent)
}
OtpAuthType.SMS -> {
val intent = Intent(this@MainActivity, ValidateSMSActivity::class.java)
startActivity(intent)
}
OtpAuthType.Whatsapp -> {
val intent = Intent(this@MainActivity, ValidateWhatsappActivity::class.java)
startActivity(intent)
}
OtpAuthType.MagicOtp -> {
val intent = Intent(this@MainActivity, ValidateMagicOtpActivity::class.java)
startActivity(intent)
}
OtpAuthType.MagicLink -> {
val intent = Intent(this@MainActivity, ValidateMagicLinkActivity::class.java)
startActivity(intent)
}
}Java
import com.fazpass.fia.objects.OtpAuthType;
switch (Constants.otpPromise.getAuthType()) {
case OtpAuthType.HE:
Intent intent = new Intent(MainActivity.this, ValidateHEActivity.class);
startActivity(intent);
break;
case OtpAuthType.Miscall:
Intent intent = new Intent(MainActivity.this, ValidateMiscallActivity.class);
startActivity(intent);
break;
case OtpAuthType.SMS:
Intent intent = new Intent(MainActivity.this, ValidateSMSActivity.class);
startActivity(intent);
break;
case OtpAuthType.Whatsapp:
Intent intent = new Intent(MainActivity.this, ValidateWhatsappActivity.class);
startActivity(intent);
break;
case OtpAuthType.MagicOtp:
Intent intent = new Intent(MainActivity.this, ValidateMagicOtpActivity.class);
startActivity(intent);
break;
case OtpAuthType.MagicLink:
Intent intent = new Intent(MainActivity.this, ValidateMagicLinkActivity.class);
startActivity(intent);
break;
}Recently, there are 6 auth type:
HE (Header Enrichment) uses network to verify the user. User will not receive an OTP and does not need to input any OTP. Only available if user uses data carrier for internet.
To validate this auth type, call validateHE() method.
First callback will be fired if there is an error.
Second callback will be fired if validation has been successful.
Kotlin
Constants.otpPromise.validateHE(
{ err ->
// handle error here...
},
{
val transactionId = Constants.otpPromise.transactionId
// with the transactionId, check for the user verified status here...
}
)Java
Constants.otpPromise.validateHE(
err -> {
// handle error here...
},
() -> {
String transactionId = Constants.otpPromise.getTransactionId();
// with the transactionId, check for the user verified status here...
}
)This OTP will call user's phone number.
User has to fill the last several digits of the caller's phone number. Digit count can be obtained with digitCount property.
There is also a miscall listener method listenToMiscall(). See code snippet down below for example usage.
To validate this auth type, call validate() method and fill the inputted user OTP in the parameter.
First callback will be fired if there is an error.
Second callback will be fired if validation has been successful.
Kotlin
val digitCount = Constants.otpPromise.digitCount
// miscall OTP listener
Constants.otpPromise.listenToMiscall { otp ->
// validate OTP method
Constants.otpPromise.validate(
otp,
{ err ->
// handle error here...
},
{
val transactionId = Constants.otpPromise.transactionId
// with the transactionId, check for the user verified status here...
}
)
}Java
Int digitCount = Constants.otpPromise.getDigitCount();
// miscall OTP listener
Constants.otpPromise.listenToMiscall(otp -> {
// validate OTP method
Constants.otpPromise.validate(
otp,
err -> {
// handle error here...
return null;
},
() -> {
String transactionId = Constants.otpPromise.getTransactionId();
// with the transactionId, check for the user verified status here...
return null;
}
);
return null;
});This OTP will send an SMS to user's phone number.
User has to fill the OTP sent to their SMS inbox. Digit count can be obtained with digitCount property.
To validate this auth type, call validate() method and fill the inputted user OTP in the parameter.
First callback will be fired if there is an error.
Second callback will be fired if validation has been successful.
Kotlin
val digitCount = Constants.otpPromise.digitCount
Constants.otpPromise.validate(
"USER_INPUTTED_OTP",
{ err ->
// handle error here...
},
{
val transactionId = Constants.otpPromise.transactionId
// with the transactionId, check for the user verified status here...
}
)Java
Int digitCount = Constants.otpPromise.getDigitCount();
Constants.otpPromise.validate(
"USER_INPUTTED_OTP",
err -> {
// handle error here...
return null;
},
() -> {
String transactionId = Constants.otpPromise.getTransactionId();
// with the transactionId, check for the user verified status here...
return null;
}
);This OTP will send a Whatsapp message to user's Whatsapp number.
User has to fill the OTP sent to their Whatsapp. Digit count can be obtained with digitCount property.
To validate this auth type, call validate() method and fill the inputted user OTP in the parameter.
First callback will be fired if there is an error.
Second callback will be fired if validation has been successful.
Kotlin
val digitCount = Constants.otpPromise.digitCount
Constants.otpPromise.validate(
"USER_INPUTTED_OTP",
{ err ->
// handle error here...
},
{
val transactionId = Constants.otpPromise.transactionId
// with the transactionId, check for the user verified status here...
}
)Java
Int digitCount = Constants.otpPromise.getDigitCount();
Constants.otpPromise.validate(
"USER_INPUTTED_OTP",
err -> {
// handle error here...
return null;
},
() -> {
String transactionId = Constants.otpPromise.getTransactionId();
// with the transactionId, check for the user verified status here...
return null;
}
);User will be redirected to Whatsapp and required to send a prepared message to a specified phone number. Then user has to input the incoming OTP from their Whatsapp to your application.
With this auth type, call launchWhatsappForMagicOtp() method to launch Whatsapp.
First callback will be fired if there is an error when launching Whatsapp.
Second callback will be fired if Whatsapp launched successfully.
After Whatsapp has been launched successfully, you can validate the OTP using validate() method.
Check documentation about Whatsapp auth type above.
Kotlin
Constants.otpPromise.launchWhatsappForMagicOtp(
{ err ->
// handle error here...
},
{
// show user a textfield to input the incoming OTP,
// then call the validate Whatsapp method (Constants.otpPromise.validate())
}
)Java
Constants.otpPromise.launchWhatsappForMagicOtp(
err -> {
// handle error here...
return null;
},
() -> {
// show user a textfield to input the incoming OTP,
// then call the validate Whatsapp method (Constants.otpPromise.validate())
return null;
}
);User will be redirected to Whatsapp and required to send a prepared message to a specified phone number. Then user has to click on the link from their Whatsapp.
With this auth type, call launchWhatsappForMagicLink() method to launch Whatsapp.
First callback will be fired if there is an error.
Second callback will be fired if validation has been successful.
Kotlin
Constants.otpPromise.launchWhatsappForMagicLink(
{ err ->
// handle error here...
},
{
val transactionId = Constants.otpPromise.transactionId
// with the transactionId, check for the user verified status here...
}
)Java
Constants.otpPromise.launchWhatsappForMagicLink(
err -> {
// handle error here...
return null;
},
() -> {
String transactionId = Constants.otpPromise.getTransactionId();
// with the transactionId, check for the user verified status here...
return null;
}
);Get the transactionId like this:
Kotlin
val transactionId = Constants.otpPromise.transactionIdJava
String transactionId = Constants.otpPromise.getTransactionId();Then check the segment down below on how to check if user has been successfully verified.
Caution
You have to call method otpActivity() directly in the activity onCreate() method.
Otherwise your app might crash.
Caution
You have to call method otpActivity() or otp() using FragmentActivity OR AppCompatActivity as context.
Otherwise your app might crash.
Tip
If you use android jetpack compose for UI builder, it's okay to change ComponentActivity to one of these activities.
Because AppCompatActivity extends FragmentActivity, which extends ComponentActivity.
See the reference here.
A successfully validated OTP DOES NOT mean that the user has also been successfully verified. To check for user's verified status, check this Server Documentation.