diff --git a/ChromeCustomTabsClient.js b/ChromeCustomTabsClient.android.js similarity index 53% rename from ChromeCustomTabsClient.js rename to ChromeCustomTabsClient.android.js index 4e332dd..e5af6e8 100644 --- a/ChromeCustomTabsClient.js +++ b/ChromeCustomTabsClient.android.js @@ -1,4 +1,4 @@ 'use strict'; var { NativeModules } = require('react-native'); -module.exports = NativeModules.ChromeCustomTabsClient; \ No newline at end of file +module.exports = NativeModules.ChromeCustomTabsClient; diff --git a/ChromeCustomTabsClient.ios.js b/ChromeCustomTabsClient.ios.js new file mode 100644 index 0000000..6f8bf10 --- /dev/null +++ b/ChromeCustomTabsClient.ios.js @@ -0,0 +1,7 @@ +'use strict'; + +var { Linking } = require('react-native'); + +// Fall back to Linking.openURL on iOS. +module.exports.launchCustomTab = Linking.openURL; +module.exports.mayLaunchUrl = function(url) {}; diff --git a/README.md b/README.md index 0cc4c63..4398bf6 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,26 @@ project(':ReactNativeChromeCustomTabs').projectDir = new File(rootProject.projec 4. Import and register the module in your `MainActivity.java` file: ```java import com.dstaley.ReactNativeChromeCustomTabs.ChromeCustomTabsPackage; // <-- Import +``` + +### For React Native >= v0.29 +```java +public class MyReactNativeHost extends ReactNativeHost { + @Override + protected List getPackages() { + return Arrays.asList( + ... + new ChromeCustomTabsPackage(), // <-- Register + ... + ); + } +} +``` + +### For React Native v0.19 - v0.28 + +```java public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { private ReactInstanceManager mReactInstanceManager; @@ -53,6 +72,27 @@ ChromeCustomTabsClient.mayLaunchUrl('http://i.imgur.com/6ogeF96.gif'); ChromeCustomTabsClient.launchCustomTab('http://i.imgur.com/xjdem.gif'); ``` +## Customization + +You can supply a `CustomTabsIntentEditor` to customize the CustomTabsIntent produced by +this package. + +```java + new ChromeCustomTabsPackage(new CustomTabsIntentEditor() { + @Override + public void customize(Context context, CustomTabsIntent.Builder builder) { + builder + .addDefaultShareMenuItem() + .setShowTitle(true) + .enableUrlBarHiding(); + } + }) +``` + +For a full description of the available options, see the official documentation for +[CustomTabsIntent.Builder](https://developer.android.com/reference/android/support/customtabs/CustomTabsIntent.Builder.html) +and the [custom tabs implementation guide](https://developer.chrome.com/multidevice/android/customtabs#implementationguide). + ## License MIT \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 58535ae..d7fa3d4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -23,7 +23,6 @@ android { dependencies { compile fileTree(dir: "libs", include: ["*.jar"]) - compile "com.android.support:appcompat-v7:23.0.1" - compile "com.android.support:customtabs:23.1.0" + compile "com.android.support:customtabs:25.1.0" compile "com.facebook.react:react-native:0.17.+" } \ No newline at end of file diff --git a/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/ChromeCustomTabsModule.java b/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/ChromeCustomTabsModule.java index e5d840b..371bdef 100644 --- a/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/ChromeCustomTabsModule.java +++ b/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/ChromeCustomTabsModule.java @@ -2,45 +2,43 @@ import android.app.Activity; import android.content.Intent; -import android.os.Bundle; import android.net.Uri; -import android.widget.Toast; +import android.support.annotation.Nullable; import android.support.customtabs.CustomTabsIntent; -import android.support.v7.app.AppCompatActivity; -import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.modules.core.DeviceEventManagerModule; -import java.util.Map; -import java.util.HashMap; - -import com.dstaley.ReactNativeChromeCustomTabs.CustomTabActivityHelper; - public class ChromeCustomTabsModule extends ReactContextBaseJavaModule implements CustomTabActivityHelper.ConnectionCallback { - Activity mActivity; private CustomTabActivityHelper mCustomTabActivityHelper; private ReactApplicationContext mContext; + private CustomTabsIntentEditor mIntentEditor; - public ChromeCustomTabsModule(ReactApplicationContext reactContext, Activity activity) { + ChromeCustomTabsModule( + ReactApplicationContext reactContext, + @Nullable CustomTabsIntentEditor intentEditor) { super(reactContext); - mActivity = activity; mContext = reactContext; - String packageName = CustomTabsHelper.getPackageNameToUse(mActivity); + mIntentEditor = intentEditor; mCustomTabActivityHelper = new CustomTabActivityHelper(); mCustomTabActivityHelper.setConnectionCallback(this); - mCustomTabActivityHelper.bindCustomTabsService(mActivity, reactContext.getApplicationContext()); + mCustomTabActivityHelper.bindCustomTabsService(reactContext.getApplicationContext()); } private void sendEvent(String eventName) { - if (mContext.hasActiveCatalystInstance()) { - mContext - .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) - .emit(eventName, null); + try { + if (mContext.hasActiveCatalystInstance()) { + mContext + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit(eventName, null); + } + } catch (RuntimeException e) { + // Work around a race condition in RN < 0.38.0, resulting in + // a RuntimeException of "Attempt to call JS function before JS bundle is loaded." + // Fixed in react-native#6a45f05. } } @@ -71,7 +69,22 @@ public void mayLaunchUrl(String url) { @ReactMethod public void launchCustomTab(String url) { - CustomTabsIntent customTabsIntent = new CustomTabsIntent.Builder(mCustomTabActivityHelper.getSession()).build(); - mCustomTabActivityHelper.openCustomTab(mActivity, customTabsIntent, Uri.parse(url), null); + Activity activity = getCurrentActivity(); + if (activity == null) { + return; + } + + CustomTabsIntent.Builder builder = + new CustomTabsIntent.Builder(mCustomTabActivityHelper.getSession()); + if (mIntentEditor != null) { + mIntentEditor.customize(activity, builder); + } + CustomTabActivityHelper.openCustomTab(activity, builder.build(), Uri.parse(url), + new CustomTabActivityHelper.CustomTabFallback() { + @Override + public void openUri(Activity activity, Uri uri) { + activity.startActivity(new Intent(Intent.ACTION_VIEW, uri)); + } + }); } -} \ No newline at end of file +} diff --git a/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/ChromeCustomTabsPackage.java b/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/ChromeCustomTabsPackage.java index da843f5..77534b3 100644 --- a/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/ChromeCustomTabsPackage.java +++ b/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/ChromeCustomTabsPackage.java @@ -17,16 +17,29 @@ public class ChromeCustomTabsPackage implements ReactPackage { - Activity mActivity; + private final CustomTabsIntentEditor mIntentEditor; + public ChromeCustomTabsPackage() { + this((CustomTabsIntentEditor) null); + } + + public ChromeCustomTabsPackage(CustomTabsIntentEditor intentEditor) { + mIntentEditor = intentEditor; + } + + /** + * @deprecated + * The activity parameter is no longer used. + */ + @Deprecated public ChromeCustomTabsPackage(Activity activity) { - mActivity = activity; + this((CustomTabsIntentEditor) null); } @Override public List createNativeModules(ReactApplicationContext reactContext) { List modules = new ArrayList<>(); - modules.add(new ChromeCustomTabsModule(reactContext, mActivity)); + modules.add(new ChromeCustomTabsModule(reactContext, mIntentEditor)); return modules; } @@ -39,4 +52,4 @@ public List> createJSModules() { public List createViewManagers(ReactApplicationContext reactContext) { return Arrays.asList(); } -} \ No newline at end of file +} diff --git a/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/CustomTabActivityHelper.java b/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/CustomTabActivityHelper.java index 322aae4..b949d4a 100644 --- a/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/CustomTabActivityHelper.java +++ b/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/CustomTabActivityHelper.java @@ -105,10 +105,10 @@ public void setConnectionCallback(ConnectionCallback connectionCallback) { * Binds the Activity to the Custom Tabs Service. * @param activity the activity to be binded to the service. */ - public void bindCustomTabsService(Activity activity, Context context) { + public void bindCustomTabsService(Context context) { if (mClient != null) return; - String packageName = CustomTabsHelper.getPackageNameToUse(activity); + String packageName = CustomTabsHelper.getPackageNameToUse(context); if (packageName == null) return; mConnection = new ServiceConnection(this); @@ -170,4 +170,4 @@ public interface CustomTabFallback { void openUri(Activity activity, Uri uri); } -} \ No newline at end of file +} diff --git a/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/CustomTabsIntentEditor.java b/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/CustomTabsIntentEditor.java new file mode 100644 index 0000000..55175df --- /dev/null +++ b/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/CustomTabsIntentEditor.java @@ -0,0 +1,13 @@ +package com.dstaley.ReactNativeChromeCustomTabs; + +import android.content.Context; +import android.support.customtabs.CustomTabsIntent; + +/** + * Callback for customizing the creation of a CustomTabsIntent. + * This is called just before a custom tab is opened. + */ +public interface CustomTabsIntentEditor { + + void customize(Context context, CustomTabsIntent.Builder builder); +} diff --git a/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/MainActivity.java b/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/MainActivity.java index dc3a5ca..0edcc18 100644 --- a/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/MainActivity.java +++ b/android/src/main/java/com/dstaley/ReactNativeChromeCustomTabs/MainActivity.java @@ -28,7 +28,7 @@ protected void onCreate(Bundle savedInstanceState) { .setBundleAssetName("index.android.bundle") .setJSMainModuleName("index.android") .addPackage(new MainReactPackage()) - .addPackage(new ChromeCustomTabsPackage(this)) + .addPackage(new ChromeCustomTabsPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build();