Getting Started With the Halliday Android Kotlin SDK
Prerequisites
To use our Kotlin Passkeys API with your Android app, be sure that your project supports at least Android API 34+. This is due to a requirement from Google's Credential Manager API, which acts as the interface for Android passkeys.
Installation
Our latest library is published to mavenCentral
! The latest version is 1.0.1
.
To include our package, include the following line to your build.gradle
or build.gradle.kts
file
implementation "xyz.halliday.sdk:hallidayClient-kotlin-android:1.0.1"
implementation("xyz.halliday.sdk:hallidayClient-kotlin-android:1.0.1")
Setting Up Passkeys Infrastructure
In order for Google services to create and authenticate passkeys for your users, you will need to host an /.well-known/assetlinks.json
file on your server.
- If you have published your application, take note of the domain which you registered your app, and host the file under that domain (i.e.
www.your-domain.com/.well-known/assetlinks.json
). In this example, the domain specified in the file would beyour-domain.com
- If you are testing, you can temporarily host this file on AWS or some other server. The domain will be that server's domain
The assetlinks.json
file has the following format:
[
{
"relation": [
"delegate_permission/common.handle_all_urls",
"delegate_permission/common.get_login_creds"
],
"target": {
"namespace": "android_app",
"package_name": "your-android-package-name",
"sha256_cert_fingerprints": [
"aa:bb:cc:dd:ee:ff:gg:...:zz"
]
}
}
]
- The
package_name
should be the same name as defined in your application-layerbuild.gradle
file:
android {
namespace: 'android_app'
compileSdk: 34 // NOTE: Passkeys only work on API 34+
defaultConfig {
applicationId: "your-android-package-name"
}
}
- To get the
SHA256_cert_fingrprint
:- If you have published your app, then you should be able to find this through the same process as when you registered your app with Google. The SHA256_cert_fingerprint should be from whichever key that signed the application before publishing to Google.
- Otherwise, you can run the command
keytool -list -v -keystore ~/.android/debug.keystore -storepass android -keypass android
(for AndroidStudio) to list the SHA256 fingerprint.
You can also use this helpful tool to generate your assetlinks.json
file here
Note: When creating and testing passkeys, you must log in to your Google Account on your device or emulator, and have set up biometrics and/or screen lock on the device.
To learn more about setting up the assetlinks.json
file, please refer to The Android Developer Reference on Passkeys.
Initialize
You can access the HallidayClient in your classes after initializing the HallidayClient with the following arguments:
- apiKey -- Your Halliday sandbox or production API Key
- blockchainType -- The blockchain that your app runs on. By default, this is set to
BlockchainType.MUMBAI
, but you can set it to other chains enumerated in theBlockchainType
enum class - sandbox -- By default, this value is true so all requests are sent to our sandbox testing environment. This means all blockchain transactions will also be executed on testnets. When releasing your product, be sure to switch
BlockchainType
to be a mainnet type, and switchsandbox = false
to hit our production servers. - domain -- This should be set to the domain in which your app registers with Google, as it is crucial for setting up passkeys properly. See the Setting Up Passkeys Infrastructure section for more details.
- name -- Your application's name
- context -- The Android application context in which this client is integrated in.
import org.halliday.client.HallidayClientInterface
import org.halliday.client.initializeHallidayClient
val hallidayClient: HallidayClientInterface = initializeHallidayClient(apiKey, BlockchainType.MUMBAI, sandbox = true, "yourDomain", "yourAppName", context)
hallidayClient.isInitialized() // should return true if the client has been set up and initialized
Usage
The following snippet shows an integration of the HallidayClient for passkeys creation and login:
import org.halliday.client.HallidayClientInterface
import org.halliday.client.initializeHallidayClient
class SignUpFragment: Fragment () {
// Initialize the HallidayClient
val hallidayClient: HallidayClientInterface = initializeHallidayClient(apiKey, BlockchainType.MUMBAI, true, "halliday.xyz", "testApp", requireActivity())
val inGamePlayerId = "test-player-id" // The user's UNIQUE id in your application
val userName: String = "test_userName" // The user's in app name
val appName: String = "testApp" // The application's name
// Register a new client to use passkeys with your app
try {
hallidayClient.register(inGamePlayerId, userName, appName, requireActivity())
} catch (e: Exception) {
Log.e("signUp", "Error creating passkey: ${e.message}")
}
// If no exceptions, the user should have successfully registered a passkey.
// The user can now log in via passkeys, and approve transactions with their Halliday Smart Account with that passkey!
// Get the user details, i.e. userId and signer keyAddress
val userDetails: UserDetails = hallidayClient.getLoggedInUserDetails()
val userId: String = userDetails.userId
val keyAddress: String = userDetails.keyAddress
}
class SignInFragment: Fragment () {
// Initialize the HallidayClient
val hallidayClient: HallidayClientInterface = initializeHallidayClient(apiKey, BlockchainType.MUMBAI, true, "halliday.xyz", "testApp", requireActivity())
val inGamePlayerid = "test-player-id" // The user's UNIQUE in-game player id
// Log in the user with an existing passkey
// The function will prompt the user to sign in with an existing passkey.
try {
hallidayClient.login(inGamePlayerId)
} catch (e: Exception) {
if (e is NoPasskeyException) {
Log.e("login", "No passkeys found for user. Please create one before logging in.")
// Redirect users back to createPasskey page
}
Log.e("login", "Error logging in user: ${e.message}")
// Redirect users back to pre-login page
}
// Get the user details, i.e. userId, userName, and non-custodial keyAddress
val userDetails: UserDetails = hallidayClient.getLoggedInUserDetails()
Log.d("login", "Got user details: $userDetails") // We have overridden the toString() method so it prints nicely!
}
Once the user is logged in, they can leverage their Halliday Smart Account to build and send gas-sponsored transactions, which are approved with their passkey. For the user, this experience will be just like Apple Pay, where they will authenticate with their existing passkey once again to sign and approve the transaction.
// Set up client and log in the user
suspend fun sendTransaction() {
// Set up the transaction details
val targetAddress = "0x..." // The target address for the transaction
val value = "0" // The amount of native tokens to send with the transaction
val calldata = "0x..." // The calldata for the contract function.
val sponsor_gas = true // Please make sure you have contacted us to enable gas sponsorship!
val transaction: GetTransactionResponse = hallidayClient.callContract(targetAddress, value, calldata, sponsor_gas, requireActivity())
Log.d("Transaction", "Transaction result: $transaction") // toString() has been overridden to print nicely!
}
Beta: Session Keys
Using biometrics to approve transactions every time can still be tedious for users. With the Halliday SDK, however, you can enable session keys for your players, so that for a certain period of time, all transactions will be auto-signed and auto-approved with the session key. This way, players no longer need to input biometric data for every transaction for as long as the session key is active. See our Session Keys page for more information.
Common Issues and Errors
- To test passkeys, you must run your application on an emulator or actual device. This is because Android unit tests do not run the entire android environment, but the entire context is needed for creating and accessing passkeys
- You must also log into your Google account on your emulator or device, and set up biometrics / screen lock on the device to create and authenticate with passkeys.
- If you get the error
Cannot get create options
, be sure to check if you are logged in!
- If you get the error
- If you get the error
Cannot get sync account
, try powering off then on the emulator or device. This may occur if you immediately test after logging in to your Google account on an emulator. - If you get the error
The incoming request cannot be validated
, this means that yourassetlinks.json
file has not been properly set up. Check the following:- The
domain
you initialized the HallidayClient with ininitializeHallidayClient
matches the domain under which you host theassetlinks.json
file - The
package_name
andnamespace
fields in theassetlinks.json
file matches theapplicationId
andnamespace
fields in yourbuild.gradle
file, respectively - The
SHA256_Cert_fingerprint
is from the same certificate that signs your application
- The
Updated 4 days ago