Making library in android

Creating and Publishing an Android Library

Introduction

Our lives as Android developers would be a lot harder if not for all those third-party libraries out there that we love to include in our projects. In this tutorial, you will learn how to give back to the developer community by creating and publishing your own Android libraries, which people can effortlessly add and use in their projects.

1. Creating an Android Library

If your library is going to be composed of only Java classes, packaging it as a JAR and distributing it using a file host is perhaps the quickest and easiest way to share it. If you were to create it from the console, the following command would suffice:

This tutorial however, shows you how to work with more complex libraries that contain not just Java classes, but also various types of XML files and resources. Such libraries are created as Android library modules and are usually packaged as AAR files.

Let’s create a simple Android library that offers a custom View to developers who use it.

Step 1: Add a New Module

To begin, add a new Android module to your project by selecting New > New Module from the File menu. You will be shown the following screen, which offers lots of choices:

Select Android Library and press Next. In the form that follows, enter a name for your library and press Next. I’ll be calling this library mylittlelibrary.

In the last screen, select Add no Activity and press Finish.

Your project will now have two modules, one for the app and one for the library. Here’s what its structure looks like:

Step 2: Create a Layout

Create a new layout XML by right-clicking on the res folder of your library module and selecting New > XML > Layout XML File. Name it my_view.xml.

To keep this tutorial simple, we’ll be creating a custom View that has two TextView widgets inside a LinearLayout . After adding some text to the TextView widgets, the layout XML file should look like this:

Step 3: Create a Java Class

Create a new Java class and name it MyView.java. Make sure to put this file in the src directory of the library module–not the app module.

To make this class behave as a View , make it a subclass of the LinearLayout class. Android Studio will prompt you to add a few constructors to the class. After adding them, the new class should look like this:

As you can see, we now have two constructors. To avoid adding initialization code to each constructor, call a method named initialize from each constructor. Add the following code to each constructor:

In the initialize method, call inflate to associate the layout we created in the previous step with the class.

2. Using the Library Locally

Now that the library is ready, let’s make use of it in the app module of the same project in order to make sure that there are no issues. To do so, add it as a compile dependency in the build.gradle file of the app module:

Create a new Java class, MainActivity, inside the app module. Make it a subclass of the Activity class and override its onCreate method.

Inside the onCreate method, create an instance of the custom view using its constructor. Pass it to the setContentView method so that it fills all the screen space of the Activity :

Your Activity is now ready. After adding it to the app manifest, build your project and deploy your app to an Android device. You should be able to see the custom view when the app starts.

3. Publishing Your Library on Bintray

Bintray is a popular platform you can use to publish Android libraries. It is free and easy to use.

Start by creating an account on Bintray. After signing in to your account, you will see that you already own six repositories. You can either use one of them or create a new repository. For this tutorial, I will be using the repository called maven, which is a Maven repository.

Читайте также:  Сколько времени заряжается андроид

Visit your profile page and click the Edit button. On the next page, click the API Key link to view your API key.

Make a note of the key, because you will be needing it to authenticate yourself when using the Bintray plugin.

Step 1: Add Necessary Plugins

To interact with Bintray in Android Studio, you should include the Bintray plugin in the dependencies of your project’s build.gradle file.

Because you will be uploading the library to a Maven repository, you should also add the Maven plugin as shown below.

Step 2: Apply the Plugins

Open the build.gradle file of your library module and add the following code to apply the plugins we added in the previous step.

Step 3: Specify POM Details

The Bintray plugin will look for a POM file when it uploads the library. Even though the Maven plugin generates it for you, you should specify the value of the groupId tag and the value of the version tag yourself. To do so, use the group and version variables in your gradle file.

If you are familiar with Maven and you are wondering why we didn’t specify the value of the artifactId tag, it is because the Maven plugin will, by default, use the name of your library as the artifactId .

Step 4: Generate a Sources JAR

To conform to the Maven standards, your library should also have a JAR file containing the library’s source files. To generate the JAR file, create a new Jar task, generateSourcesJar, and specify the location of the source files using the from function.

Step 5: Generate a Javadoc JAR

It is also recommended that your library has a JAR file containing its Javadocs. Because you currently don’t have any Javadocs, create a new Javadoc task, generateJavadocs, to generate them. Use the source variable to specify the location of the source files. You should also update the classpath variable so that the task can find classes that belong to the Android SDK. You can do this by adding the return value of the android.getBootClasspath method to it.

Next, to generate a JAR from the Javadocs, create a Jar task, generateJavadocsJar, and pass the destinationDir property of generateJavadocs to its from function. Your new task should look like this:

To make sure the generateJavadocsJar task only starts when the generateJavadocs task has completed, add the following code snippet, which uses the dependsOn method to order the tasks:

Step 6: Include the Generated JAR files

To include the source and Javadoc JAR files in the list of artifacts, which will be uploaded to the Maven repository, you should add the names of their tasks to a configuration called archives. To do so, use the following code snippet:

Step 7: Run Tasks

It is now time to run the tasks we created in the previous steps. Open the Gradle Projects window and search for a task named install.

Double-click it to run the tasks associated with the library module. Once it’s finished running, you will have everything you need to publish your library, a valid POM file, an AAR file, a sources JAR, and a Javadocs JAR.

Step 8: Configure the Bintray Plugin

To configure the plugin, you should use the bintray closure in your Gradle file. First, authenticate yourself using the user and key variables, corresponding to your Bintray username and API key respectively.

On Bintray, your library will reside inside a Bintray package. You should provide details about it using the intuitively named repo , name , licenses , and vcsUrl parameters of the pkg closure. If the package doesn’t exist, it will be created automatically for you.

When you upload files to Bintray, they will be associated with a version of the Bintray package. Therefore, pkg must contain a version closure whose name property is set to a unique name. Optionally, you can also provide a description, release date, and Git tag using the desc , released , and vcsTag parameters.

Finally, to specify the files that should be uploaded, set the value of the configuration parameter to archives.

This is a sample configuration:

Step 9: Upload Files Using the Bintray Plugin

Open the Gradle Projects window again and search for the bintrayUpload task. Double-click it to begin uploading the files.

Once the task completes, open a browser to visit your Bintray package’s details page. You will see a notification that says that you have four unpublished files. To publish these files, click the Publish link.

4. Using the Library From Bintray

Your library is now available as a Bintray package. Once you share the URL of your Maven repository, along with the group ID, artifact ID, and version number, any developer can access your library. For example, to use the library we created, developers would have to include the following code snippet:

Note that the developer has to explicitly include your repository in the list of repositories before adding the library as a compile dependency.

Читайте также:  Инженерное меню андроид 11 realme

5. Adding the Library to JCenter

By default, Android Studio searches for libraries in a repository called JCenter. If you include your library in the JCenter repository, developers won’t have to add anything to their repositories list.

To add your library to JCenter, open a browser and visit your Bintray package’s details page. Click the button labeled Add to JCenter.

You will then be taken to a page that lets you compose a message. You can use the Comments field to optionally mention any details about the library.

Click the Send button to begin Bintray’s review process. Within a day or two, the folks at Bintray will link your library to the JCenter repository and you will be able to see the link to JCenter on your package’s details page.

Any developer can now use your library without changing the list of repositories .

Conclusion

In this tutorial, you learned how to create a simple Android library module and publish it to both your own Maven repository and to the JCenter repository. Along the way, you also learned how to create and execute different types of gradle tasks.

To learn more about Bintray, visit Bintray’s user manual.

Источник

Considerations when creating Android libraries

If you are an Android developer, chances are you might have been working on your own Android libraries. A library is a useful way to create a reusable set of features that need to be integrated through different apps (or even different libraries).

A library is a self-contained package including code and resources required to execute some functionality. Importing a library in our Android app is the same process as importing a .JAR file in a Java app, except that for Android the library file has the extension .AAR, which extends for Android archive (however, Android apps can also import libraries with a .JAR extension). There are detailed guides on the Internet on how to create Android libraries, but in this article I would like to focus on some aspects that are more subjective, and not always defined in every guide. We will discuss today the following aspects:

  • Keeping in mind exposed functionality
  • Kotlin/Java interaction
  • Exposing resources
  • Transitive dependencies and strategies to solve them

Keep in mind which functionality will be exposed

A library likely offers an interface to the user to access its functionality. Regardless of whether the particular library encapsulates UX functionality, some interface towards an API… there will also be some classes and methods that are not relevant to the end-user, and that they will likely be exposed. How to prevent this?

  • Use properly visibility modifiers. If you are using Java, tend to prioritise the default modifier package private. If you are using Kotlin, lend towards internal(this means that it will be visible for the module).
  • Sometimes, packages need to be transitively exposed. For instance, think of the following setup for a library we are working with:

My library has a dependency on My module, which is an internal module used by the library. My library needs to access some data from the module (let’s say, some internal models). We need to declare them as public. But then, every class that integrates the library will be able to access those models, which is rather uncomfortable.

You could name the package of the model as internal (for instance, my.package.internal.models). This is a common industry practice, and it *should* discourage the usage of those classes. For instance, Retrofit or OkHttp have the same naming for their internal classes.

Since Kotlin 1.4 there is an Explicit API mode, that enforces to operate on a short of library mode. In order to activate it, write the following on your Gradle file:

The setup is fairly straightforward: one mode will be strict and trigger errors, and the less strict mode will trigger warnings.

When the Explicit API mode is activated, visibility modifiers are required for declarations if the default visibility means they will be public. This will enforce visibility to be specifically declared.

Kotlin/Java interaction

Kotlin should not be a strange word for you anymore. And this means that you should be aware of how Kotlin and Java interact with each other, and keep this in mind to ensure that the library can be called seamlessly. This means: you might be calling your Kotlin library from a Java codebase, or you might be calling your Java library from a Kotlin codebase. In those cases you will need to put an extra dose of attention, to improve the experience of the users implementing your library.

Package level functions

Since Java does not allow standalone functions outside classes, all the standalone functions or properties that you declare in a file file.kt will be compiled as static methods of a class called org.file.FileKt:

This would compile in a Java class like the following:

Of course, having the classes automatically named is something that we want to avoid. By using the annotation @JvmName we can specify the name of the destination class:

Читайте также:  The dark knight risen для android

You can also use file:JvmMultifileClass to combine the top-level members from multiple files into a single class.

Instance fields

If you need to expose any underlying property in Kotlin to a Java class, use the annotation @JvmField . This will make the property accessible from your Java class.

Functions with default parameters

When you define a function in Kotlin with default parameters, you don’t need to continuously pass them when you are calling that function. If they are not specified, the default value is taken.

Java does not support default parameters, so what happens when we call these functions in Java? By default, we need to specify all the parameters, and this does not scale well if you have been using default parameters in Kotlin. This is where we can use @JvmOverloads

Let’s consider the following fictional function in Kotlin:

The function is using the annotation @JvmOverloads, and it also has two default parameters as arguments. From a Java point of view, this function will compile as follows:

The advantages are obvious when we are dealing with long constructors that are using some default parameters, and that we do not need to specify again in our Java classes.

Nothing generics in Kotlin

A Kotlin type with a generic parameter Nothing is exposed as a raw type in Java. This should be avoided, since raw types are rarely used in Java.

Companion functions and constants

When Companion functions and constants are rawly compiled and accessed from Java, they are only available as instance methods on a static Companion field. For instance, the following Kotlin class:

is exposed as follows in Java:

Using a @JvmStatic annotation for the function makes the compiled code cleaner:

For companion constants, is better to use the annotation @JvmField , since @JvmStatic creates a weird getter. For instance, consider the following companion constant:

Annotating the companion value with @JvmField will result again in a Java code much more comprehensive:

Exposing resources

Something that some folks are not aware of is that, by default, all the resources in an Android library are public! This means that everything that is included in your res folder (images, drawables, strings…). It is somehow a convoluted and counterintuitive method, but in order to make all your resources private, you should define at least one resource as public.

A good practice is to make public only a string specifying the library name. Do this when you start developing your app, and you will not have to worry about the external visibility of your resources anymore (that is, unless you really want to make them public).

Be aware of transitive dependencies

Libraries might depend on external dependencies, and ideally you want to deliver all of them within the same .AAR. Otherwise, the user will need to manually include them, and this is complicated to handle.

On the other hand, we might be enforcing the user to include certain libraries that might conflict with the ones included at their app level.

There is no silver bullet here, and a few strategies to solve this issue.

Include all the transitive dependencies

A. AAR file can be generated including all the dependencies it needs. This is not done automatically out of the box by the .AAR file, and needs to be somehow hacked.

You can add and call a Gradle task that copies all the dependencies into the .AAR when this is packed:

There is a facilitation plugin, fat-aar, that ameliorates this task. It does a few more things, but I found it a bit unstable (by the time I have to release a new library version, a new Gradle version is also available that generally breaks the plugin).

Strategies to force or remove dependencies

Also known as hell. Let’s say that your main app includes a RandomLibrary version 2.1. The app needs to include your FancyLibrary, which includes the version 3.1 of RandomLibrary, with a lot of breaking changes. You might need to force the resolution of a particular version, or remove some libraries from the build. In projects heavily modularised this can exponentially increase the complexity of your build script.

The following Gradle lines can exclude a library from the build:

Designing and writing a library is more than packaging a few classes. Ideally, a phase of design needs to take place where you think about the structure and classes’ organization. Your company structure will affect this heavily as well (Do you have different teams working on different modules? Do you have an open repository policy? Do you have any restrictions to use external libraries? How much politics influence your development work?)

I write my thoughts about Software Engineering and life in general on my Twitter account. If you have liked this article or it did help you, feel free to share, 👏 it and/or leave a comment. This is the currency that fuels amateur writers.

Источник

Оцените статью