1

Has anyone had any success configuring digits for react native for android? Pretty stuck adding Digits as a dependency in MainActivity.java.

Is there a way to add it as a package with the .addPackage line?

update: I've wrapped digits, but am having trouble getting it to compile. If anyone is invested in this and wants to help me answer this question: Gradle @aar dependency resolution in react-native project I would be much obliged.

Community
  • 1
  • 1
Isaac Madwed
  • 986
  • 9
  • 23
  • It is in the roadmap of react-native-fabric-digits – Nishanth Shankar Nov 04 '15 at 06:32
  • True, saw that. I'm looking for any help setting it up now, or ideally a general tutorial on setting up any android packages with react-native. – Isaac Madwed Nov 04 '15 at 16:19
  • As in Crashlytics Digits, correct? Have you been successful in getting Crashlytics integrated into your RN app? I've heard some have had issues. If you have tips, I'd love to hear them. I'll have to do it soon as well. – Chris Geirman Nov 04 '15 at 17:19
  • I'm working on getting it up and running now, will answer when I've put together the npm package. – Isaac Madwed Nov 05 '15 at 17:35

1 Answers1

2

Using Fabric is a huge pain if you don't adhere exactly to the Twitter way of doing things.

Here is my implementation:

DigitsPackage.java

package com.yourapp.rctdigits;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class DigitsPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new DigitsModule(reactContext));
        return modules;
    }

    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

DigitsModule.java

package com.yourapp.rctdigits;

import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;

import com.digits.sdk.android.AuthCallback;
import com.digits.sdk.android.Digits;
import com.digits.sdk.android.DigitsClient;
import com.digits.sdk.android.DigitsException;
import com.digits.sdk.android.DigitsOAuthSigning;
import com.digits.sdk.android.DigitsSession;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableNativeMap;
import com.twitter.sdk.android.core.TwitterAuthConfig;
import com.twitter.sdk.android.core.TwitterAuthToken;
import com.twitter.sdk.android.core.TwitterCore;

import java.util.Map;

import io.fabric.sdk.android.Fabric;

public class DigitsModule extends ReactContextBaseJavaModule {
    private static final String META_DATA_KEY = "io.fabric.ApiKey";
    private static final String META_DATA_SECRET = "io.fabric.ApiSecret";
    private static final String TAG = "RCTDigits";
    volatile DigitsClient digitsClient;
    private ReactApplicationContext mContext;

    public DigitsModule(ReactApplicationContext reactContext) {
        super(reactContext);
        mContext = reactContext;
    }

    @Override
    public String getName() {
        return "DigitsManager";
    }

    @ReactMethod
    public void launchAuthentication(final Callback successCallback, final Callback errorCallback) {
        TwitterAuthConfig authConfig = getTwitterConfig();
        Fabric.with(mContext, new TwitterCore(authConfig), new Digits());

        AuthCallback callback = new AuthCallback() {
            @Override
            public void success(DigitsSession session, String phoneNumber) {
                // Do something with the session and phone number
                Log.i(TAG, "authentication successful");

                TwitterAuthConfig authConfig = TwitterCore.getInstance().getAuthConfig();
                TwitterAuthToken authToken = (TwitterAuthToken) session.getAuthToken();
                DigitsOAuthSigning oauthSigning = new DigitsOAuthSigning(authConfig, authToken);
                Map<String, String> authHeaders = oauthSigning.getOAuthEchoHeadersForVerifyCredentials();
                WritableNativeMap authHeadersNativeMap = new WritableNativeMap();

                for (Map.Entry<String, String> entry : authHeaders.entrySet()) {
                    authHeadersNativeMap.putString(entry.getKey(), entry.getValue());
                }

                WritableNativeMap result = new WritableNativeMap();
                result.putMap("oAuthHeaders", authHeadersNativeMap);
                result.putString("userId", String.valueOf(session.getId()));
                result.putString("phoneNumber", session.getPhoneNumber());

                successCallback.invoke(result);
            }

            @Override
            public void failure(DigitsException exception) {
                // Do something on failure
                Log.e(TAG, "error " + exception.getMessage());
                errorCallback.invoke(exception.getMessage());
            }
        };

        int themeId = mContext.getResources().getIdentifier("CustomDigitsTheme", "style", mContext.getPackageName());
        Digits.getInstance().authenticate(callback, themeId);
    }

    private TwitterAuthConfig getTwitterConfig() {
        String key = getMetaData(META_DATA_KEY);
        String secret = getMetaData(META_DATA_SECRET);

        return new TwitterAuthConfig(key, secret);
    }

    // adapted from http://stackoverflow.com/questions/7500227/get-applicationinfo-metadata-in-oncreate-method
    private String getMetaData(String name) {
        try {
            ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
                    mContext.getPackageName(),
                    PackageManager.GET_META_DATA
            );

            Bundle metaData = ai.metaData;
            if (metaData == null) {
                Log.w(TAG, "metaData is null. Unable to get meta data for " + name);
            } else {
                String value = metaData.getString(name);
                return value;
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

MainActivity.java

Add this line: .addPackage(new DigitsPackage()) to your instance manager

res/values/themes.xml

I use a custom theme

<?xml version="1.0" encoding="utf-8"?>
<!-- Digits theme. -->
<resources>
    <style name="CustomDigitsTheme" parent="android:Theme.Holo.Light">
        <item name="android:textColorPrimary">@android:color/black</item>
        <item name="android:textColorSecondary">@android:color/darker_gray</item>
        <item name="android:windowBackground">@android:color/white</item>
        <item name="android:textColorLink">#ffe74c3c</item>
        <item name="android:colorAccent">#ffe74c3c</item>
    </style>
</resources>

android/app/build.gradle

Add

repositories {
    maven {
        url 'https://maven.fabric.io/public'
    }
}

and

dependencies {
    compile('com.digits.sdk.android:digits:1.8.0@aar') {
        transitive = true;
    }
}

android/build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
        maven { url 'https://maven.fabric.io/public' }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.1'
        classpath 'io.fabric.tools:gradle:1.+'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        mavenLocal()
        jcenter()
    }
}

AndroidManifest.xml

add

  <meta-data
    android:name="io.fabric.ApiKey"
    android:value="YOUR_API_KEY" />
  <meta-data
    android:name="io.fabric.ApiSecret"
    android:value="YOUR_API_SECRET" />

js

var DigitsManager = require("react-native").NativeModules.DigitsManager;

DigitsManager.launchAuthentication((loginResponse) => {
    Log.debug("[Digits]", "login successful", loginResponse);
}, (error) => {
    Log.warn("[Digits]", "Login failed", error);
});

I should probably make a Github repo with this and the iOS version...

Corentin S.
  • 5,750
  • 2
  • 17
  • 21
  • Thanks @Corentin! I wish I'd see yours a little earlier, the part that I ended up getting hung up on was adding the maven bit to the app's `android/build.gradle`. My implementation is a little different, but pretty similar, will be putting it up on Github with installation instructions soon as well. Hopefully it can help people out when they're developing packages like this. – Isaac Madwed Nov 06 '15 at 14:25
  • One question, why did you add `maven { url 'https://maven.fabric.io/public' }` and `classpath 'io.fabric.tools:gradle:1.+'` to the `buildscript` and not just the remote repo to the repos in `allprojects`? – Isaac Madwed Nov 06 '15 at 15:32
  • Good question... I don't really remember ^^ – Corentin S. Nov 06 '15 at 16:50