|
| 1 | +--- |
| 2 | +title: Android |
| 3 | +icon: android |
| 4 | +ordinal: 7 |
| 5 | +--- |
| 6 | + |
| 7 | +### Github repo |
| 8 | + |
| 9 | +[slp-wallet-sdk-android](https://github.com/Bitcoin-com/slp-wallet-sdk-android) |
| 10 | + |
| 11 | +### Supported Android Versions |
| 12 | + |
| 13 | +5.0+ |
| 14 | + |
| 15 | +#### Warning |
| 16 | + |
| 17 | +On Android versions prior to Android 6.0 Marshmallow, disabling the secure lock screen (reconfiguring it to None, Swipe, or another mode which does not authenicate the user) will have the following conquences: |
| 18 | + |
| 19 | +- Loss of the BCH and tokens held at the wallet address. |
| 20 | +- Loss of access to the private key that controls the BCH and tokens held at the wallet address. |
| 21 | + |
| 22 | +Tokens and any extra BCH at the wallet address can only be recovered if the mnemonic has been previously backed up. |
| 23 | + |
| 24 | +### Installation |
| 25 | + |
| 26 | +#### Gradle |
| 27 | + |
| 28 | +Add JitPack to the list of repositories in your top level `build.gradle` file for the project: |
| 29 | + |
| 30 | +```groovy |
| 31 | +allprojects { |
| 32 | + repositories { |
| 33 | + google() |
| 34 | + jcenter() |
| 35 | + maven { url 'https://jitpack.io' } // Add this repository |
| 36 | + } |
| 37 | +} |
| 38 | +``` |
| 39 | + |
| 40 | +In the module 'build.gradle' file, add the dependency: |
| 41 | + |
| 42 | +```groovy |
| 43 | +dependencies { |
| 44 | + // ... |
| 45 | +
|
| 46 | + implementation 'com.github.Bitcoin-com:slp-wallet-sdk-android:0.4' |
| 47 | + implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava' |
| 48 | +
|
| 49 | +} |
| 50 | +``` |
| 51 | + |
| 52 | +Excluding guava is required to avoid conflicts. |
| 53 | + |
| 54 | +##### Binary compatibility |
| 55 | + |
| 56 | +In the current version of the SDK, some items need to be removed for binary compatibility. |
| 57 | + |
| 58 | +Add these packaging options to your module `build.gradle`. |
| 59 | + |
| 60 | +```groovy |
| 61 | +android { |
| 62 | + // ... |
| 63 | +
|
| 64 | + packagingOptions { |
| 65 | + exclude 'lib/x86_64/darwin/libscrypt.dylib' |
| 66 | + exclude 'lib/x86_64/freebsd/libscrypt.so' |
| 67 | + exclude 'lib/x86_64/linux/libscrypt.so' |
| 68 | + } |
| 69 | +} |
| 70 | +``` |
| 71 | + |
| 72 | +### Get Started |
| 73 | + |
| 74 | +```kotlin |
| 75 | +import com.bitcoin.slpwallet.SLPWallet |
| 76 | + |
| 77 | +// Create a new wallet on mainnet, or load one previously created. |
| 78 | +val slpWallet: SLPWallet = SLPWallet.loadOrCreate(context, Network.MAIN) |
| 79 | + |
| 80 | +val slpWalletFromPhrase: SLPWallet = SLPWallet.fromMnemonic( |
| 81 | + context, |
| 82 | + Network.MAIN |
| 83 | + "rare genre crumble sport burger laugh lecture reject exhaust hello express pass" |
| 84 | + ) |
| 85 | + |
| 86 | +// A wallet is created on mainnet if one does not exist already. |
| 87 | +val slpWallet: SLPWallet = SLPWallet.getInstance(context) |
| 88 | +``` |
| 89 | + |
| 90 | +### Addresses + Mnemonic |
| 91 | + |
| 92 | +The wallet resuses two addresses that shares mnemonic. |
| 93 | + |
| 94 | +- The SLP address on m/44'/245'/0'/0/0. |
| 95 | +- The BCH address on m/44'/145'/0'/0/0. |
| 96 | + |
| 97 | +All BCH change will be sent to the BCH address while all token change is sent to the SLP address, separating the two if they were not already. This helps protect against accidental spending of BCH that contains SLP, by wallets are not aware of SLP, which would result in loss of coins. |
| 98 | + |
| 99 | +```kotlin |
| 100 | +slpWallet.mnemonic // "rare", "genre", "crumble", "sport", "burger", "laugh", "lecture", "reject", "exhaust", "hello", "express", "pass" |
| 101 | +slpWallet.slpAddress // simpleledger:qr6wa5eemn0fl3vghvk5cr480s3fqtgnevkaxny9x7 |
| 102 | +slpWallet.bchAddress // bitcoincash:qr6wa5eemn0fl3vghvk5cr480s3fqtgnev6xdg39cq |
| 103 | + |
| 104 | +``` |
| 105 | + |
| 106 | +#### Token and BCH Balances |
| 107 | + |
| 108 | +The balances, including both tokens and BCH, are available as LiveData. |
| 109 | + |
| 110 | +```kotlin |
| 111 | +slpWallet.balance.observe(this, Observer { balanceList: List<BalanceInfo> -> |
| 112 | + var balances = "" |
| 113 | + for (balance in balanceList) { |
| 114 | + val nf = getTokenNumberFormat(balance.decimals, balance.ticker) |
| 115 | + balances += "${nf.format(balance.amount)}\n" |
| 116 | + } |
| 117 | + balancesText.text = balances |
| 118 | +}) |
| 119 | +``` |
| 120 | + |
| 121 | +The BCH balance item has an emtpy `tokenId` of `""`. |
| 122 | + |
| 123 | +```kotlin |
| 124 | +interface BalanceInfo { |
| 125 | + var tokenId: String |
| 126 | + var amount: BigDecimal |
| 127 | + var ticker: String? |
| 128 | + var name: String? |
| 129 | + var decimals: Int? |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +To refresh the current balance: |
| 134 | + |
| 135 | +```kotlin |
| 136 | +slpWallet.refreshBalance() |
| 137 | +``` |
| 138 | + |
| 139 | +### Send Token |
| 140 | + |
| 141 | +```kotlin |
| 142 | +private val compositeDisposable = CompositeDisposable() |
| 143 | + |
| 144 | +// ... |
| 145 | + |
| 146 | +val tokenId = "73bf34eb6cd6879fc75b0e91ad82ef61a6bf2f10adb38a067a25b30f9a644cea" |
| 147 | +val amount = BigDecimal(1) |
| 148 | +val toAddress = "simpleledger:qpfp0tfafxfq52mdpperlyschmmh6scfgse80v7a4p" |
| 149 | + |
| 150 | +slpWallet.sendToken(tokenId, amount, toAddress) |
| 151 | + .subscribeOn(Schedulers.io()) |
| 152 | + .subscribe( |
| 153 | + { txid: String -> |
| 154 | + Timber.d("sendToken() was successful, with txid: $txid") |
| 155 | + }, |
| 156 | + { e: Throwable -> |
| 157 | + Timber.e("Error when sending. $e") |
| 158 | + } |
| 159 | + ).addTo(compositeDisposable) |
| 160 | +``` |
| 161 | + |
| 162 | +The example above uses Rx, but the status of the send task is also available as LiveData: |
| 163 | + |
| 164 | +```kotlin |
| 165 | +slpWallet.sendStatus.observe(this, Observer { task: ProgressTask<String?> -> |
| 166 | + var sendStatus = "" |
| 167 | + when (task.status) { |
| 168 | + TaskStatus.IDLE -> { |
| 169 | + sendStatus = "" |
| 170 | + } |
| 171 | + TaskStatus.UNDERWAY -> { |
| 172 | + sendStatus = "Sending..." |
| 173 | + } |
| 174 | + TaskStatus.SUCCESS -> { |
| 175 | + sendStatus = "Sent tx ${task.result}" |
| 176 | + } |
| 177 | + TaskStatus.ERROR -> { |
| 178 | + sendStatus = "Error. ${task.message}" |
| 179 | + } |
| 180 | + } |
| 181 | + sendStatusText.text = sendStatus |
| 182 | +}) |
| 183 | +``` |
| 184 | + |
| 185 | +Once a send has been completed, you can reset the status to `IDLE`: |
| 186 | + |
| 187 | +```kotlin |
| 188 | +slpWallet.clearSendStatus() |
| 189 | +``` |
| 190 | + |
| 191 | +### UI |
| 192 | + |
| 193 | +Some convenience methods are included to make it easier to display tokens in your UI. |
| 194 | + |
| 195 | +#### Formatting Amounts |
| 196 | + |
| 197 | +This will display the amount to the full number of decimal places permitted by the coin, preceded by the ticker. |
| 198 | + |
| 199 | +```kotlin |
| 200 | +import com.bitcoin.slpwallet.getTokenNumberFormat |
| 201 | + |
| 202 | +val nf: NumberFormat = getTokenNumberFormat(decimals, ticker) |
| 203 | +val text: String = nf.format(amount) // "AAR 123.45" |
| 204 | +``` |
| 205 | + |
| 206 | +### Logging |
| 207 | + |
| 208 | +This library uses [Timber](https://github.com/JakeWharton/timber) for logging, but does not plant it's own tree. Plant a tree like this when your application starts to see the logs: |
| 209 | + |
| 210 | +```kotlin |
| 211 | +override fun onCreate(savedInstanceState: Bundle?) { |
| 212 | + super.onCreate(savedInstanceState) |
| 213 | + |
| 214 | + if (BuildConfig.DEBUG) { |
| 215 | + Timber.plant(Timber.DebugTree()) |
| 216 | + } |
| 217 | + |
| 218 | + // ... |
| 219 | +} |
| 220 | +``` |
0 commit comments