Skip to content

Commit

Permalink
implement api tokens in library and sample
Browse files Browse the repository at this point in the history
  • Loading branch information
klinker41 committed Nov 13, 2016
1 parent e998e80 commit 129159c
Show file tree
Hide file tree
Showing 10 changed files with 43 additions and 26 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -5,3 +5,4 @@ local.properties
*.iml
.idea/
*.log
api_keys.properties
8 changes: 7 additions & 1 deletion README.md
Expand Up @@ -40,7 +40,7 @@ intent.launchUrl(this, Uri.parse(url));
Simple, right? You can pass any parameters into the builder that you would normally use in a custom tab such as colors and toolbar actions (however, many of those actions are not currently supported by this library, though they will be displayed if the library ends up opening a custom tab instead of displaying the article natively). I also added on a few extras to the builder that you can use to customize the UI more to your liking:

<pre lang="java">
ArticleIntent intent = new ArticleIntent.Builder(this)
ArticleIntent intent = new ArticleIntent.Builder(this, apiKey)
.setToolbarColor(primaryColor)
<b>.setAccentColor(accentColor)</b>
<b>.setTheme(ArticleIntent.THEME_DARK)</b>
Expand All @@ -51,6 +51,12 @@ intent.launchUrl(this, Uri.parse(url));

You can check out the sample application for more information and implementation notes.

## Obtaining an API Key

I distribute API keys for free to whoever wants one, I just ask that you give us a contact email address and a short description about how you're planning on using it. You can sign up for one at https://klinkerapps-article.herokuapp.com/. After signing up, simply pass it into the article intent builder as seen in the example above.

If you want to try out the sample app, you'll also have to register for an API token. After that, you need to rename the `api_keys.properties.example` file to `api_keys.properties` and it's contents should just be your token: `API_KEY=<your-api-token>`.

## How It Works

This library leverages a node.js backend that I have deployed on AWS that does all of the heavy lifting for processing an article. On the backend, we go and grab the article and strip out anything in it that we don't want as soon as we get a URL from the app. We'll then return the results to the library and cache them in a MongoDB instance so that next time we get a request for the same article, it is significantly faster to load.
Expand Down
1 change: 1 addition & 0 deletions api_keys.properties
@@ -0,0 +1 @@
API_KEY=***REMOVED***
1 change: 1 addition & 0 deletions api_keys.properties.example
@@ -0,0 +1 @@
API_KEY=<your-api-key-here>
Expand Up @@ -70,10 +70,6 @@ public void onCreate(Bundle savedInstanceState) {

this.url = getIntent().getDataString();

if (url == null) {
throw new RuntimeException("EXTRA_URL must not be null.");
}

if (DEBUG) {
Log.v(TAG, "loading article: " + url);
}
Expand All @@ -87,7 +83,7 @@ public void onCreate(Bundle savedInstanceState) {
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
}

this.utils = new ArticleUtils();
this.utils = new ArticleUtils(getIntent().getStringExtra(ArticleIntent.EXTRA_API_TOKEN));
this.utils.loadArticle(url, this);

this.primaryColor = getIntent().getIntExtra(ArticleIntent.EXTRA_TOOLBAR_COLOR,
Expand Down
Expand Up @@ -78,6 +78,9 @@ public final class ArticleIntent {
public static final String EXTRA_ACCENT_COLOR =
"xyz.klinker.android.article.extra.EXTRA_ACCENT_COLOR";

public static final String EXTRA_API_TOKEN =
"xyz.klinker.android.article.extra.EXTRA_API_TOKEN";

/**
* Boolean extra that enables the url bar to hide as the user scrolls down the page
*/
Expand Down Expand Up @@ -300,8 +303,9 @@ public static final class Builder {
private ArrayList<Bundle> mActionButtons = null;
private boolean mInstantAppsEnabled = true;

public Builder(Context context) {
public Builder(Context context, String apiToken) {
mIntent = new Intent(context, ArticleActivity.class);
mIntent.putExtra(EXTRA_API_TOKEN, apiToken);
}

/**
Expand Down
Expand Up @@ -24,9 +24,8 @@
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import xyz.klinker.android.article.ArticleLoadedListener;
import xyz.klinker.android.article.api.ArticleApi;
import xyz.klinker.android.article.api.Article;
import xyz.klinker.android.article.api.ArticleApi;

/**
* Helper for working with the article apis.
Expand All @@ -37,8 +36,8 @@ class ArticleUtils {

private ArticleApi api;

ArticleUtils() {
this.api = new ArticleApi();
ArticleUtils(String apiToken) {
this.api = new ArticleApi(apiToken);
}

/**
Expand Down
Expand Up @@ -104,33 +104,36 @@ public enum Environment {
/**
* Creates a new API access object with the release environment.
*/
public ArticleApi() {
this(Environment.RELEASE);
public ArticleApi(String apiToken) {
this(Environment.RELEASE, apiToken);
}

/**
* Creates a new API access object that will connect to the correct environment.
*
* @param environment the Environment to use to connect to the APIs.
*/
private ArticleApi(Environment environment) {
this(environment == Environment.DEBUG ? API_DEBUG_URL : API_RELEASE_URL);
private ArticleApi(Environment environment, String apiToken) {
this(environment == Environment.DEBUG ? API_DEBUG_URL : API_RELEASE_URL, apiToken);
}

/**
* Creates a new API access object that will automatically attach your API key to all
* requests.
*/
private ArticleApi(String baseUrl) {
httpClient.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl url = request.url().newBuilder().build();
request = request.newBuilder().url(url).build();
return chain.proceed(request);
}
});
private ArticleApi(String baseUrl, final String apiToken) {
if (httpClient.interceptors().size() == 0) {
httpClient.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl url = request.url().newBuilder()
.addQueryParameter("api_token", apiToken).build();
request = request.newBuilder().url(url).build();
return chain.proceed(request);
}
});
}

Retrofit.Builder builder =
new Retrofit.Builder()
Expand Down
6 changes: 6 additions & 0 deletions sample/build.gradle
Expand Up @@ -16,6 +16,10 @@

apply plugin: 'com.android.application'

def propsFile = rootProject.file('api_keys.properties')
def apiKeys = new Properties()
apiKeys.load(new FileInputStream(propsFile))

android {
compileSdkVersion Integer.parseInt(project.COMPILE_SDK)
buildToolsVersion project.BUILD_TOOLS_VERSION
Expand All @@ -25,6 +29,8 @@ android {
targetSdkVersion Integer.parseInt(project.TARGET_SDK)
versionCode Integer.parseInt(project.VERSION_CODE)
versionName project.VERSION_NAME

buildConfigField("String", "API_KEY", "\"${apiKeys['API_KEY']}\"")
}

buildTypes {
Expand Down
Expand Up @@ -132,7 +132,7 @@ public void onClick(View view) {
}

private void openArticle(String url) {
ArticleIntent intent = new ArticleIntent.Builder(this)
ArticleIntent intent = new ArticleIntent.Builder(this, BuildConfig.API_KEY)
.setToolbarColor(getResources().getColor(R.color.articlePrimary))
.setAccentColor(getResources().getColor(R.color.articleAccent))
.setTheme(ArticleIntent.THEME_AUTO)
Expand Down

0 comments on commit 129159c

Please sign in to comment.