-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
AnkiDroid API
Audience: This page is for Android app developers. AnkiDroid users can ignore it.
Starting From AnkiDroid v2.5, notes can be added directly to AnkiDroid's database without sending any intents via a simple API library released on the LGPL license. This is advantageous for developers and end-users, as it allows quickly adding flashcards to AnkiDroid in bulk, without any user intervention. Additionally, an app-specific custom model can be used, so that developers can ensure that their content will be formatted into sensible and beautiful flashcards.
Please add your app to this list if it supports the instant-add API
- Aedict3
- AnkiEditor
- AnkiMate
- Bildkortsappen
- Hanping Chinese Dictionary Pro
- Hanping Cantonese Dictionary
- Kanji Study
- Kata
- ReadDict
- Takoboto Japanese Dictionary
- Word of the day
First things first, you should add the following dependency to your module's build.gradle
file:
dependencies {
implementation 'com.ichi2.anki:api:1.1.0alpha6'
}
Release Notes:
Here is a very simple example of adding a new note to AnkiDroid. See the sample app for a more complete / detailed example including permission checking, duplicate checking, storing and retrieving the model / deck ID, using tags, using a custom model, etc.
/** Check the AnkiDroid package is available to the API before instantiating
* You need to implement deckExists(), modelExists(), getDeckId(), and getModelId().
* Note: On SDK 23+ you must also do a permission check before calling API methods! **/
if (AddContentApi.getAnkiDroidPackageName(context) != null) {
// API available: Add deck and model if required, then add your note
final AddContentApi api = new AddContentApi(context);
long deckId = deckExists()? getDeckId(): api.addNewDeck("My app name");
long modelId = modelExists()? getModelId(): api.addNewBasicModel("com.something.myapp");
api.addNote(modelId, deckId, new String[] {"日の出", "sunrise"}, null);
} else {
// Fallback on ACTION_SEND Share Intent if the API is unavailable
Intent shareIntent = ShareCompat.IntentBuilder.from(context)
.setType("text/plain")
.setSubject("日の出")
.setText("sunrise")
.getIntent();
if (shareIntent.resolveActivity(context.getPackageManager()) != null) {
context.startActivity(shareIntent);
}
}
Note: To add multiple notes you should use addNotes(), which can often be orders of magnitude faster than calling addNote() in a loop.
The API requires the permission com.ichi2.anki.permission.READ_WRITE_DATABASE
which is defined by the main AnkiDroid app. This permission will automatically be merged into your manifest if you included the Gradle dependency above. In order to workaround this Android limitation we use dynamic permission checking to only enforce permissions on Android M and above, or for certain high risk API calls. See the sample app and the API javadoc for more details on working with permissions.
A very simple example application is available here, which gives an expected real-world implementation of the API in the form of a prototype Japanese-English dictionary. Long-press on an item in the list to send one or more cards to AnkiDroid via the share button on the contextual toolbar.
Perform the following manual tests to check that your app is working correctly. If your app fails to pass any of these tests, please refer to the sample app again for a reference implementation that passes all of the below tests.
Test 1: Basic testing (Android 5.1 and below)
- Install the latest dev version of AnkiDroid
- Send some flashcards from your app to AnkiDroid via the API using a deck "Your App Name"
- Open AnkiDroid, check that a deck called "Your App Name" is there, and click on it to start studying the cards.
- Flip through a few cards and check that they are formatted correctly
- Open the Card Browser and check that all of the cards which you sent are there
- Open the AnkiDroid settings, go to Advanced, and uncheck "Enable AnkiDroid API"
- Try to add a card from your app again. It should correctly detect that the API is unavailable (due to disabling it in the previous step), and fallback on an intent based approach (see section on intents below).
- Check that the front and back of the flashcard are sent to AnkiDroid in the correct order when using intents
- Uninstall AnkiDroid
- Check that your app does not give the user the option to send cards to AnkiDroid (since it's not installed)
Test 2: Permissions test with Android Marshmallow
- Use a device or emulator running Android 6.0 or higher and latest dev version of AnkiDroid
- Try to add cards to AnkiDroid from your app
- Android should prompt the user whether or not they want to grant your app the
READ_WRITE_DATABASE
permission - Choose "deny"
- Your app should correctly fallback on adding via an ACTION_SEND intent
- Try to add cards to AnkiDroid from your app again
- This time choose to grant the permission
- Check that the cards were added to AnkiDroid correctly as per previous tests
While we strongly recommend using the Instant-Add API, if the user has a version of AnkiDroid that doesn't support the API, or if they've denied permission to your app to access it, you should fall back on an intent-based approach, which is supported by all versions of AnkiDroid.
The disadvantage of the intent-based approach compared with the API, is that you can't send multiple cards at once, you leave the user on their own to format your content into flashcards, and most importantly -- the user has to go from your app to AnkiDroid, and then press some buttons to complete the add before they can resume what they were doing in your app, which detracts from the user experience. This is why we only recommend using it as a fall-back when the API is not available.
The ACTION_SEND
intent is a universal intent for sharing data with other apps in Android. AnkiDroid expects the front text to be in the subject, and the back text to be in the main content. Use ShareCompat
to build the intent so that information about your app is automatically sent to AnkiDroid with the intent:
Intent shareIntent = ShareCompat.IntentBuilder.from(context)
.setType("text/plain")
.setText("Sunrise")
.setSubject("日の出")
.getIntent();
if (shareIntent.resolveActivity(context.getPackageManager()) != null) {
context.startActivity(shareIntent);
}
Note: CREATE_FLASHCARD is deprecated from AnkiDroid 2.5. Please use ACTION_SEND instead.
Another intent which is currently supported by AnkiDroid for backwards compatibility is the org.openintents.action.CREATE_FLASHCARD
intent. Fields are submitted with intent extras SOURCE_TEXT
and TARGET_TEXT
for the front and back respectively:
Intent intent = new Intent();
intent.setAction("org.openintents.indiclash.CREATE_FLASHCARD");
intent.putExtra("SOURCE_TEXT", "日の出");
intent.putExtra("TARGET_TEXT", "Sunrise");
startActivity(intent);
AnkiDroid v2.5 supports background syncing via an experimental intent which can be sent from Tasker. Note: a "server is busy" error will be shown if you try to sync more often than once every 5 minutes.
Sync Intent [
Action:com.ichi2.anki.DO_SYNC
Cat:Default
Mime Type:
Data:
Extra:
Extra:
Package:
Class:
Target:Activity ]
Note: A previous version of this documentation had a Target type of Service instead. Since a recent (mid 2017) Tasker update this no longer works, and Target must be changed to Activity in order to function properly, as discussed at https://groups.google.com/forum/#!topic/tasker/KJISOpinu4U.
As an example, if you import this XML file into a Tasker profile, it will trigger AnkiDroid to sync when the power is plugged in. See the Tasker FAQ for instructions on how to import profiles. For the App Automate you can import this example Flow to sync every 8 hours and a quarter hour after you closed the app.
The Instant-add API is a high-level wrapper around the lower level ContentProvider based API. The ContentProvider API contains more features than the Instant-add API, but is more complicated to use. Check the source code itself and the accompanying FlashCardsContract file in the API. The open-source AnkiDroid-Wear app may also be useful as an example of how to use the low-level API.
We welcome contributions to create a more developer-friendly API for the features in the ContentProvider, as well as contributions to the low-level API to add new features, and of course contributions to improve / update documentation.