📜 ⬆️ ⬇️

Is it a bird? This is a plane? No, this is your user's token flying to a new phone.

Hi, Habr!

Today I will talk about the API for developers from Google. It will be about how not to force the user to log in again in the application after transferring data, or, to put it more precisely, how to use the Android Account Transfer API.

Most likely, each of us bought a new smartphone and had to transfer all important information and applications from the old one to it. Now this process has become quite simple thanks to technology Tap & Go . But there is one thing. You have to login again wherever possible. And what if this application is a type of fitness tracker, where I logged in once and forgot? Recover password? Headache again. You can say: “But there is a Smart Lock!”, And you will be right, but we must take into account all the cases. What if a person forgot to save a password? Or is he just paranoid and does not store passwords? Or is the application not implemented Smart Lock ? I think that there will always be reasons to forget the authorization data. But now there is a solution, and you can ease the burden of transferring the authentication data of your users. Only here it is not for everyone. Yes, and effectively earn at least a year.
')
Three questions follow from this:

1. What is the Account Transfer API?
2. Why is it not for everyone?
3. Why effectively earn at least a year?

Required Requirements


As I said before, the Account Transfer API allows developers to transfer authorization information, including token and account information, from the old phone to the new one. And what is needed for this?

And here we run into the saddest part necessary to implement this technology.

What do you need to make it work?

1. Old device with Android version 4.0.1 or higher (API Level 14).
Not such a problem, you say, and I agree with that, but look further.

2. The new device to which we want to copy data must be running an OS not lower than Android 8.0 (API Level 26).

This is the answer to the question “Why does it work effectively for at least a year?”. Yes, this year many devices will receive an Android update to Oreo, but they are unlikely to be sold from an already built-in OS with the necessary API Level. Most likely, the stock versions will remain on the shelves, which will have the maximum Android Marshmallow on board. And after the purchase will have to update them manually. And this is the key moment for our feature. It is very likely that the user will first transfer their data to the device, and only then update it.

Not to be unfounded, I will show you the information of Google from February 5, 2018.



3. Both devices must have Google Play version 11.2.0 and higher. This should not be a big problem, unless, of course, you support devices without Google Play. They transfer to organize fail.

4. You must build your APK using Google Play services of at least 11.2.0. It can become a problem only if you have reasons not to use the services of this version or not to use the services at all.

5. An already implemented AbstractAccountAuthenticator integrated with AccountManager is required. There is an excellent cycle of articles on "Habré" on implementation.

How it works?




Provided that all requirements are met, a secure wired connection or encrypted via Bluetooth is created between the phones. If during the transfer you want to check the validity of the token on your backend, then one of the devices must be connected to the Internet.

Next, the system sends a Broadcast message ( ACTION_START_ACCOUNT_EXPORT or ACTION_ACCOUNT_EXPORT_DATA_AVAILABLE ) about the readiness to start exporting data, upon receipt of which we must run the Foreground Service intended for data exchange. Those. we need to generate and send the user account data through a secure connection to the recipient device.





After that, the system sends another Broadcast message ( ACTION_ACCOUNT_IMPORT_DATA_AVAILABLE ) already to the receiving device. Here you also need to run Foreground Service and process the received information.



If a situation arises in which the service on the receiving device cannot be created at the time of transporting the data, the system will save the user data in temporary storage. Data will be received when you first start the application.



Implementation


Finally you decide to proceed with the implementation.

First you need to connect play-services-auth, if this has not been done before.

dependencies { // For Account Transfer api, use SDK version 11.2.0 or higher compile 'com.google.android.gms:play-services-auth-base:<VERSION_NUMBER>' } 

Next, declare in the manifest BroadcastReceiver and Service:

 <receiver android:name=".AccountTransferBroadcastReceiver" android:enabled="true" android:exported="true" > <intent-filter> <action android:name="com.google.android.gms.auth.START_ACCOUNT_EXPORT" /> </intent-filter> <intent-filter> <action android:name="com.google.android.gms.auth.ACCOUNT_IMPORT_DATA_AVAILABLE" /> </intent-filter> <intent-filter> <action android:name="com.google.android.gms.auth.ACCOUNT_EXPORT_DATA_AVAILABLE" /> </intent-filter> </receiver> <service android:name=".AuthenticatorService"> <intent-filter> <action android:name="android.accounts.AccountAuthenticator"/> </intent-filter> <meta-data android:name="android.accounts.AccountAuthenticator" android:resource="@xml/authenticator"/> </service> 

As described above, the service should be started when receiving the corresponding Broadcast messages:

 public class AccountTransferBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // Long running tasks, like calling Account Transfer API, shouldn't happen here. Start a // foreground service to perform long running tasks. Intent serviceIntent = AccountTransferService.getIntent(context, intent.getAction()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(serviceIntent); } else { context.startService(serviceIntent); } } } 

Well and accordingly, partial implementation of the service:

 protected void onHandleIntent(Intent intent) { String action = intent.getAction(); if (action == null) { return; } switch (action) { case AccountTransfer.ACTION_ACCOUNT_IMPORT_DATA_AVAILABLE: importAccount(); return; case ACTION_START_ACCOUNT_EXPORT: case AccountTransfer.ACTION_ACCOUNT_EXPORT_DATA_AVAILABLE: exportAccount(); return; } } private void importAccount() { // Handle to client object AccountTransferClient client = AccountTransfer.getAccountTransferClient(this); // Make RetrieveData api call to get the transferred over data. Task<byte[]> transferTask = client.retrieveData(ACCOUNT_TYPE); try { byte[] transferBytes = Tasks.await(transferTask, TIMEOUT_API, TIME_UNIT); //import logic } catch (ExecutionException | InterruptedException | TimeoutException | JSONException e) { client.notifyCompletion( ACCOUNT_TYPE, AuthenticatorTransferCompletionStatus.COMPLETED_FAILURE); return; } client.notifyCompletion( ACCOUNT_TYPE, AuthenticatorTransferCompletionStatus.COMPLETED_SUCCESS); } private void exportAccount() { byte[] transferBytes = Foo.yourOwnMethodToGetAccountTransferBytes(); AccountTransferClient client = AccountTransfer.getAccountTransferClient(this); if (transferBytes == null) { // Notifying is important. client.notifyCompletion( ACCOUNT_TYPE, AuthenticatorTransferCompletionStatus.COMPLETED_SUCCESS); return; } // Send the data over to the other device. Task<Void> exportTask = client.sendData(ACCOUNT_TYPE, transferBytes); try { Tasks.await(exportTask, TIMEOUT_API, TIME_UNIT); } catch (ExecutionException | InterruptedException | TimeoutException e) { // Notifying is important. client.notifyCompletion( ACCOUNT_TYPE, AuthenticatorTransferCompletionStatus.COMPLETED_FAILURE); return; } } 

A more detailed example can be found in the googlesamples repository .

For testing, Google suggests running the Setup Wizard command.

 $ adb shell am start -a android.intent.action.MAIN -n com.google.android.gms/.smartdevice.d2d.ui.TargetActivity 

And all this is enough for your user to forget about the headache and unnecessary actions when working with your application after reinstalling it on a new device. Perhaps this will be the key point that will make it clear to the user whether to continue using the application or delete it and forget.

Summing up, I’ll note that Google wants to minimize the time the user spends re-authorizing, and makes logical steps for this. And it would be good to support them in this direction. Although it takes some time for implementation, but it's worth it. After all, the devil is in the details.

Interesting information on this topic:

Documentation
Video Injection
Implementation example

Source: https://habr.com/ru/post/349260/


All Articles