Context
Our app shows an HTML flashcard to the user.
We have added several layers of "filters" to satisfy different groups of users:
- To satisfy chess enthusiasts, we convert any
{FEN:rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2}
block to an HTML table representing a chess board with pieces at the right position - To satisfy Chinese language learners, we convert
字
to<ruby>字<rt>zì</rt></ruby>
- ...
Original HTML → Chess transformation → Chinese transformation → ... → Final HTML to display
Problem
The number of filters is growing, leading to problems:
- Slower rendition
- Heavier download
- Bigger source code to maintain
- More bugs/crashes
- Maintenance burden
Question
So, we would like to make these separately installable apps.
For instance, a chess+Chinese enthusiast would install 3 apps:
- TheApp
- TheApp Chess plugin
- TheApp Chinese plugin
TheApp would automatically discover what plugins are installed, and call them in turn (order does not matter).
I was thinking of using an intent THEAPPTRANSFORM
, but how can I receive the list of apps that have an <intent-filter>
for THEAPPTRANSFORM
, and call them all in turn?
Speed is a major requirement. I have read that Intents are 10+ times slower than direct calls... would Parcelable help here?
If impossible, is there any other solution?
You need a dynamically installed plugin which is not part of your application. I think you have a few options for this.
Solution 1: Scripting
Ship a scripting language interpreter with your app. (eg. ruby - http://ruboto.org/). Create an interface for executing these scripts. Make a central database of such scripts, or load them from external storage. Now, you can execute these scripts and get the required result.
Solution 2: AIDL
Use a remote service in the plugin apps. Provide an AIDL for third parties to develop apps with a remote service with that AIDL. Such services should also conform to an intent filter defined by you. Now you can use packagemanager to find such services, select one and connect to it. Now you can call all the AIDL methods. This will be inter process communication using binder, for your application this will be a synchronous call. (see this SO question for details - Access remote service in different application)
Downside to this approach is that all these services need to be running when your app is running, so you have to handle the starting/stopping of these services. It will also affect the power consumption if the services are running in the background.
Solution 3: Broadcast/receiver
Third party installed apps that have a broadcast receiver with an intent filter for custom intent defined by you. Also, your app needs to have a broadcast receiver with a custom intent that the plugins can call with the result. Now, say you want to call a third party plugin for some transformation, you have to do this:
This option is entirely asynchronous, and it may take any amount of time to execute with no guaranties.
To know apps which have a broadcast reciever with THEAPPTRANSFORM as filter, you can use below code