Wings

Android library for silently sharing photos to multiple endpoints

Download .zip Download .tar.gz View on GitHub

Wings is an Android library for silently sharing photos to an extensible set of endpoints. The currently supported endpoints include:

  • Dropbox
  • Facebook
  • Google Cloud Print

Linking user accounts, selecting destinations, as well as the retry logic to ensure delivery are all handled by Wings. The application integrates with Wings APIs that are non-specific to the underlying endpoints, and Wings will take care of the rest. Wings also defines an interface for the application to add additional endpoints, so consider the above list easily extensible.

Wings started off as a component in Flying PhotoBooth and Party PhotoBooth, and has helped us publish photos reliably and efficiently over the years. We are now open-sourcing it because posting a photo should be easy, while integrating with native SDKs of the ever-growing number of service providers is anything but easy... so we hope Wings will take care of that part for you, and should you find yourself building new endpoints, make a pull request and add to the list!

Adding Wings to your project

The Wings library builds multiple artifacts—the core wings.aar and an AAR per endpoint, such as wings-dropbox.aar. You will only need to include the core library and the endpoints applicable to your application. Assuming you are building with Gradle in Android Studio, start by adding the following dependencies to your application's build.gradle.

compile 'com.groundupworks.wings:wings:1.0.4'
compile 'com.groundupworks.wings:wings-dropbox:1.0.4'  // For Dropbox
compile 'com.groundupworks.wings:wings-facebook:1.0.4' // For Facebook
compile 'com.groundupworks.wings:wings-gcp:1.0.4'      // For Google Drive or Cloud Print

Setting up the endpoints

You will find values/application.xml in some of the endpoint modules. This is where you specify credentials and configurations specific to your application. Take the Facebook endpoint for example, the following keys need to be overridden by your application.

<!-- Your app id from Facebook -->
<string name="wings_facebook__app_id">null</string>

<!-- The name of the default album to be created for storing photos -->
<string name="wings_facebook__app_album_default_name">null</string>

You will need to sign up as a Facebook Developer and register your application to obtain an app ID, then map that value to a string resource in your application with the key wings_facebook__app_id. The default album name will be overridden the same way. Note that the values you specify in your application will override the null specified in the library, so you should not directly modify application.xml in Wings.

The Dropbox endpoint will be a similar story. The integration instructions from the service providers may ask you to add stuff to your AndroidManifest.xml, you can skip that when using Wings, because the endpoint AAR will take care of that for you by merging its manifest. All you need to do is override the values in each application.xml.

Using the Wings APIs

Full documentation of the public API is available here, but the following sections will get you started.

Initializing Wings

Wings need to be initialized in the Application#onCreate().

IWingsModule module = new Wings.DefaultModule(this, looper, logger);
Wings.init(module, FacebookEndpoint.class, DropboxEndpoint.class, GoogleCloudPrintEndpoint.class);

The looper is used to run background tasks and the logger implements IWingsLogger. All endpoint classes used in your application should be passed to Wings#init().

Linking a user account

To share to a user's account, the user will link with a sharing service, which means authenticating followed by authorizing the appropriate level of access, then specifying the destination for the shared content. All of this OAuth happiness, including UI, is handled by Wings. The application is responsible for initiating the linking process from an Activity or a Fragment, as in this Facebook example.

Wings.getEndpoint(FacebookEndpoint.class).startLinkRequest(activity, fragment);

In that same Activity or Fragment, the following must be called in the onResume() and onActivityResult() for linking to complete.

Wings.getEndpoint(FacebookEndpoint.class).onResumeImpl();
Wings.getEndpoint(FacebookEndpoint.class).onActivityResultImpl(activity, fragment, requestCode, resultCode, data);

Subscribing to a link state

Each endpoint emits its own LinkEvent to the Otto Bus. A subscriber will receive the event at the time of subscription, and whenever the link state of that endpoint changes, until it unsubscribes.

To subscribe to the link state of the Facebook and Dropbox endpoints, implement the following @Subscribe-annotated methods in your Activity or Fragment, then call Wings#subscribe() and Wings#unsubscribe() in the onResume() and onPause() respectively. This will ensure the UI is initialized with the correct state, and properly updates when state changes occur.

@Subscribe
public void handleLinkEvent(FacebookEndpoint.LinkEvent event) {
    // Update Facebook UI with event.isLinked()
}

@Subscribe
public void handleLinkEvent(DropboxEndpoint.LinkEvent event) {
    // Update Dropbox UI with event.isLinked()
}

Sharing a photo

After confirming that a WingsEndpoint#isLinked(), you want to start sharing photos to that endpoint. This is done by calling Wings#share(), which internally creates a share request record in a database and triggers a background service to process that request. If the device has no connectivity at the moment, a retry will be scheduled according to a retry policy that waits longer and longer between subsequent retries should the request keep failing. The current implementation calculates retry intervals based on the Fibonacci sequence and gives up on records that has failed for more than two days.

The following call will create a share request to post a photo to the user's linked Facebook destination. That destination may be a Facebook Album associated with the user's Profile or a Page that the user has permission to publish content to. A notification will appear on the status bar once the photo has been shared.

Wings.share(filePath, FacebookEndpoint.class);

Extending Wings

If you intend to create a new endpoint, it'd probably be a good idea to fork the Git repo and add it to your project as source.

Adding Wings as source

Clone the Wings source.

$ git clone https://github.com/groundupworks/wings.git

Or if you use Submodules, add Wings as a submodule to your project.

$ git submodule add https://github.com/groundupworks/wings.git

Then from your project in Android Studio, Import Module... from the root wings folder, and you should see the list of all Wings modules. Select wings and the endpoints you want your application to share to. Complete the import, and your project's settings.gradle should now contain the Wings modules.

Now you need to add these modules as dependencies in your application's build.gradle.

dependencies {
    compile project(':wings')
    compile project(':wings-dropbox')  // For Dropbox
    compile project(':wings-facebook') // For Facebook
    compile project(':wings-gcp')      // For Google Drive or Cloud Print
}

Creating a new endpoint

To create a new endpoint, you need to implement a new WingsEndpoint. The best way to start is to look at how an existing endpoint implements all the interfaces. Once the new endpoint is created, remember to pass it to Wings#init() and consider submitting a pull request from your fork :)