
Not long ago, Yandex.Metrika announced
an open API with which you can access almost all Metric functions from your own program.
Today I want to talk a little about using this API and how to create a simple widget for Android devices based on it.
API Basics
The Yandex.Metrick API is built on the REST principle. Everything that can be controlled through the API is represented by a resource: counters, targets, filters, etc. Resource operations (reading, deleting, changing) are performed via HTTP requests to the servers of the Ya.Metrika API, each type of operation has its own HTTP method:
- GET: reading content
- POST: add resource
- PUT: Resource Change
- DELETE: delete resource
For example, to get a list of counters, you need to refer to the resources counters:
GET /counters
. For information on a single counter, refer to the resource by its identifier:
GET /counter/{id}
. For deletion, access the same resource, but using the DELETE method:
DELETE /counter/{id}
.
Input for REST calls and results can be encoded in two formats: XML and JSON. In the future, we will use JSON, as a more compact and convenient format for displaying on structures used in programming languages.
')
Naturally, working through the API is possible only with meters that can be accessed from your J. Metrics account. To identify the account owner, OAuth authentication is used. It is arranged very simply. A developer who wants to use the Ya.Metrika API registers his application (see
instructions ) and obtains an application identifier. By registering the application, you can get a
debugging OAuth token for it and immediately start working with the Metrics API. The debugging token will allow work with the meters available from the account of the developer who registered the application. The token must be passed in each HTTP request, either as an additional parameter in the URL (
...&oauth_token=<acces_token>
), or as a header in the HTTP request
Authorization: OAuth <access_token>
.
In order for the application to work with arbitrary counters, and not only with the available developer, you need a separate OAuth token for each user of the application. How to get it:
- The safest way is when a user is redirected by an application to a special Yandex page, authenticates on it, and (if he hasn’t already done so) gives the application access to his counters. After that, the user is redirected back to the application, and the URL to which the redirection is sent contains the parameter with the OAuth token for this user. The application should read this parameter and remember the token. Details of this procedure are described in the manual .
- Applications can also receive a token by directly requesting a username and password from the user, transferring them to OAuth to the Yandex server, and receiving the token in response. This method is less secure: login and password are requested and transmitted explicitly.
Through the use of REST, the simplest work with the API (read requests) is possible directly from the browser, without any coding. For example,
this request will display information about the meter in the demo account of the API Ya.Metriki.
Such a request will issue a report on the attendance of the counter.
Despite the simplicity of the REST interface, to fully use the API in a program written in a high-level language, you need to perform quite a lot of gestures: generating request URLs, sending HTTP requests and receiving results, generating and parsing JSON, handling errors, etc. To simplify life, I created a ready-made library for working with the Ya.Metrika API in Java:
Metrika4j . The library code is distributed under the Apache License, you can freely change and supplement it to your requirements. Next, I will tell you how to create a widget for Android devices using this library that displays site traffic.
Metrika4j
Metrika4j allows you to work with Yandex.Metrica, using familiar Java developer concepts (classes, function calls, types) and not thinking about low-level work with HTTP and JSON. The central interface of the library is
MetrikaApi . It has methods for working with the main entities of the Metrics: counters and reports. Work with additional entities (targets, filters, etc.) is rendered into separate mini-APIs, obtained from the main class
MetrikaApi
.
The structure of the methods roughly corresponds to the structure of the REST-calls of the Ya.Metrika API. The arguments passed to the REST call correspond to the arguments passed to the API methods (except for the report management API, which we describe separately).
Metrika4j supports out of the box two libraries for working with JSON: the
Jackson JSON processor and
org.json . For Jackson, 100% of the functionality is supported, for org.json - a minimum sufficient for working with reports: reading the list of counters and receiving reports. The org.json library is built into the Andriod API, so its use is convenient for Android applications. If necessary, the developer can use any other JSON library by implementing the
JsonMapper and
JsonObject interfaces with it.
Using Metrika4j
First you need to create an instance of
MetrikaApi
using
ApiFactory . When creating, you need to pass the user's OAuth-token:
Then, using the created instance, you can perform any operations:
Work with reports
Through the API, almost all reports that exist in Metric are available. The set of available reports is contained in the
Reports class. To build a selected report, call the
MetrikaApi.makeReportBuilder(Reports report, int counterId)
, which will return a special object -
ReportBuilder report
builder . In the report builder, you must specify the required report parameters (time interval, sorting, etc.). When all the parameters have been set, call the
ReportBuilder.build()
method, which will send the HTTP request to the Metrics API and return the report.
The report is returned in the form of a
Report object, which is a table with the results, plus some additional information (totals, a date interval to which the report relates, etc.). Each row of the result table is a
ReportItem object, data from which can be obtained by one of the
getXXX(String fieldName)
methods (similar to getting values ​​from the
ResultSet
using JDBC). The field names and the additional data returned must be specified for each report in the documentation for the Yandex.Metrica API.
A more detailed description of working with Metrika4j is contained in
Javadoc .
Widget for Android
Having such powerful tools at your disposal as API Ya.Metriki and Metrika4j, you can solve any tasks, including the creation of alternative user interfaces to Yandex.Metrica. But within the framework of this article we will limit ourselves to a more modest goal: we will create an Android widget that will show the current site traffic. The widget source code is available on GitHub in the
MetrikaWidget project. Just like the Metrika4j code, it is freely distributed with a minimum of licensing restrictions.
OAuth authorization
Let's start by creating
MetrikaApi
and authorization. The application works with only one account, so an instance of
MetrikaApi
can be made Singleton. Its code is contained in the
Globals class.
private static MetrikaApi api; public static synchronized MetrikaApi getApi(Context context) { if (api == null) {
If the application is launched for the first time and OAuth token is not yet in SharedPreferences, you need to get it. To do this, go to the URL request token:
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://oauth.yandex.ru/authorize?response_type=token&client_id=1359488e196b4bfa92615d0885b106d4")); startActivity(intent);
For the user, it will look like the opened page “Application requests access to your data on Yandex”. Suppose a user has successfully logged in and allowed access. Further interesting begins: how to transfer the token from the web interface back to our application? To do this, you need to register one of the activities in the application, as a handler for a protocol specific to our application (specific - so that our handler does not intersect with other applications). In
AndroidManifest.xml
we specify the following:
<activity android:name="ru.metrikawidget.AuthTokenActivity" android:label="OAuth"> <intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> <data android:scheme="metwd" android:host="oauthtoken"/> </intent-filter> </activity>
We registered
AuthTokenActivity as a handler for the metwd protocol for the pseudo-host oauthtoken. Now it is enough to specify the Callback URI
metwd://oauthtoken
in the
settings of the registered application , and after successful OAuth authentication of the user
AuthTokenActivity
will be called. In this activity, you need to parse the resulting string and save the token in SharedPreferences:
String fragment = getIntent().getData().getFragment(); String[] parts = fragment.split("\\&"); for (String part : parts) { if (part.startsWith("access_token=")) { String token = part.substring(param.length(), part.length());
Data retrieval
The data retrieval code for the widget is extremely simple:
MetrikaApi api = Globals.getApi(context);
The nuance is that this code can not be performed "in the forehead." The API Metrics servers respond fairly quickly, but the HTTP request itself can go to the server and back over slow and unreliable mobile channels. As a result, the widget that is waiting for a response will “freeze” from the point of view of the Android OS, and a window will be issued, offering to crash the hung application. This is clearly not what we need. Therefore, all requests to the Metrics API are performed asynchronously using the
AsyncTask class. Here is a simplified code for loading the list of counters (the full version is in the
WidgetSetupActivity class):
private class CountersLoadTask extends AsyncTask<Void, Void, Counter[]> { private ProgressDialog progressDialog; protected void onPreExecute() { progressDialog = ProgressDialog.show(...); } protected void onPostExecute(Counter[] counters) { progressDialog.dismiss(); counterList.addAll(Arrays.asList(counters));
For widgets, working with data is a little more difficult. Let's start with the fact that the widget provider that receives events “it's time to update the widget”, in Android terminology, is the
broadcast receiver . The life cycle of a broadcast receiver is short: it processes the event, and then immediately dies. If you start a stream from the event handler, then the receiver's death may occur before the stream finishes: sadness. Android developer guide strongly recommends using services for such cases. So
let's do it: the widget provider (
MetrikaWidgetProvider ) receives events and sends them for processing to the
UpdateService .
UpdateService
, in turn, uses asynchronous data loading through
AsyncTask
(otherwise, we again get the “Application Not Responding” window when waiting for a response from the API).
Widget display
Working with widgets on Android is a separate large topic that goes beyond the scope of this article and is well covered in both the Android
developer’s guide and additional articles. Therefore, I will tell you briefly, and for the details I will refer to the
source code of the classes
MetrikaWidgetProvider
and
UpdateService
.
A widget can be in three states: “data received”, “data update” and “no connection”. Updating the widget occurs on a timer or when you click on the widget.
- The data is received - the regular state of the widget, in which it displays the number of visits to the site today. In this state, the widget displays a standard bar graph - “rainbow”, which can be seen in the header of the Yandex.Metrica interface.
- Data update is an intermediate state, made solely for the convenience of the user, so that he receives visual feedback from the click on the widget. The widget enters it before sending a request to the API Metrics, and exits after the completion of the request. In this state, an inverted “rainbow” is displayed.
- No connection - a state indicating that the actual data could not be obtained. Displays a “rainbow” with reduced saturation, almost gray.
If the widget can be in the "no connection" state, it would be logical to update it when this connection appears, so that the user can immediately see the actual data. To do this, the widget provider subscribes to system events related to the change in the status of the network interface:
<receiver android:name="ru.metrikawidget.MetrikaWidgetProvider"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"/> <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> </intent-filter> ... </receiver>
When such an event is received, a check is made whether the connection has appeared, and an update is called:
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
Install Widget
The widget can be compiled from source code located in the
MetrikaWidget project.
You are not an Android developer, but you want to use the widget? No problem - you can download the finished widget. Release from
Android Market or debug build with
GitHub .

After installation, you will also have the “Ya.Metrika” application, which is actually a mini-instruction for the widget.