Giter Site home page Giter Site logo

novoda / simple-chrome-custom-tabs Goto Github PK

View Code? Open in Web Editor NEW
129.0 32.0 18.0 9.14 MB

Easy integration of Chrome Custom Tabs into your project. Just connect it to your activity, and navigate to the external website styling your tab as you wish.

License: Other

XSLT 7.49% Java 92.51%
android chrome-tabs chrome novoda open-source

simple-chrome-custom-tabs's Introduction

๐Ÿ›‘ THIS REPOSITORY IS OFFICIALLY NO LONGER UNDER MAINTENANCE since 10/02/2022 ๐Ÿ›‘

simple-chrome-custom-tabs Download

  • Navigating to external websites from your app?
  • "Yes, that one is easy"
  • Wondering how to keep the user in context?
  • "I know... it can be done using WebView, but I don't like it that much"
  • Aha! Why don't you try Chrome Custom Tabs?
  • "Integrating it into my app can be a pain..."
  • Not anymore!

simple-chrome-custom-tabs will help you with that.

Description

simple-chrome-custom-tabs provides easy integration of Chrome Custom Tabs into your project. Just connect it to your activity, and navigate to the external website styling your tab as you wish. Moreover with Custom Tabs the navigation can be nearly instantaneous!

More information about Chrome Custom Tabs available at: https://developer.chrome.com/multidevice/android/customtabs

Adding to your project

To start using this library, add these lines to the build.gradle of your project:

repositories {
    maven {
        url  "http://dl.bintray.com/novoda/maven" 
    }
}

dependencies {
    compile 'com.novoda:simple-chrome-custom-tabs:0.1.6'
}

Simple usage

  1. Initialize simple-chrome-custom-tabs, you only have to this once.
SimpleChromeCustomTabs.initialize(context);
  1. Connect simple-chrome-custom-tabs to your Activity as soon as it is resumed.
@Override
public void onResume() {
    super.onResume();
    SimpleChromeCustomTabs.getInstance().connectTo(this);
}

And don't forget to disconnect when the Activity is paused.

@Override
public void onPause() {
    SimpleChromeCustomTabs.getInstance().disconnectFrom(this);
    super.onPause();
}
  1. Navigate!
Uri url = ANY_WEBSITE_URL;
NavigationFallback fallback = ANY_FALLBACK_MECHANISM; //In case something goes wrong.
IntentCustomizer customizer = ANY_INTENT_CUSTOMIZER; //To theme your tab.

SimpleChromeCustomTabs.getInstance().withFallback(fallback)
    .withIntentCustomizer(customizer)
    .navigateTo(url, activity);

And voilร !!

External Browser simple-chrome-custom-tabs
external_browser simplechromecustomtabs

Note: Check the extended demo for further usage examples.

Links

Here are a list of useful links:

  • We always welcome people to contribute new features or bug fixes, here is how
  • If you have a problem or you feel that important functionality is missing check the Issues Page first to see if we are working on it

simple-chrome-custom-tabs's People

Contributors

ataulm avatar blundell avatar coreflodev avatar eduardb avatar fourlastor avatar friedger avatar jawnnypoo avatar joetimmins avatar juankysoriano avatar malmstein avatar meierjan avatar mr-archano avatar ouchadam avatar zegnus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

simple-chrome-custom-tabs's Issues

Runtime crash in SimpleChromeCustomTabs

Caused by android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=Http: pkg=com.android.chrome (has extras) }
    at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1904)
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1624)
    at android.app.Activity.startActivityForResult(Activity.java:3761)
    at android.app.Activity.startActivity(Activity.java:4028)
    at android.support.customtabs.CustomTabsIntent.launchUrl(CustomTabsIntent.java:163)
    at com.novoda.simplechromecustomtabs.navigation.SimpleChromeCustomTabsWebNavigator.navigateTo(SimpleChromeCustomTabsWebNavigator.java:37)

The line 37 executes when the the connected condition is true for the SimpleChromeCustomTabsWebNavigator class so it is contradictory to not find the activity.
Connection is established in the onResume() and disconnected in onPause() of the base activity.

Crash stats:
Devices affected -
Samsung 59%
HTC 19%
LG 11%
Others 11%

OS -
Lollipop 77%
Marshmallow 18%
Kitkat 4 5%

So pretty much affects all Android devices.

Consider predefined navigation fallbacks

What about considering facilitating even more the selection of an alternative strategy for navigation if no support for chrome custom tabs is found?

Possible options:

  • on fallback navigate with default browser.
  • on fallback navigate to webview (and this will present a webview styled as the failed custom tab)

Provide HTTP request error fallback

At the moment, in case of HTTP error (403. 503, ...) could facilitate the customisation of a behaviour, as the moment the forced one is the classic "dinosaur game" of chrome.

The main use case that this would cover could be something like:

Upon website navigation error (http request failed) I want to perform customised action.

Examples of customised actions could be displaying an snackbar, dialog, navigate to activities or for example to an static customised error website.

Min SDK 15

Hi,
I'm trying to implement your library but my app is for > 15 SDK while your library is for > 16 SDK.
I have to use tools:overrideLibrary="com.novoda.simplechromecustomtabs" to force usage
Why don't you support all versions?

java.lang.NoSuchMethodError crash on Android 7.1

java.lang.NoSuchMethodError: No static method startActivity(Landroid/app/Activity;Landroid/content/Intent;Landroid/os/Bundle;)V in class Landroid/support/v4/app/ActivityCompat; or its super classes (declaration of 'android.support.v4.app.ActivityCompat' appears in /data/user/0/net.nextbike.v3/files/.jrebel/load-bundles/libraries89_support-compat.zip)
at android.support.customtabs.CustomTabsIntent.launchUrl(CustomTabsIntent.java:200)
at com.novoda.simplechromecustomtabs.navigation.SimpleChromeCustomTabsWebNavigator.navigateTo(SimpleChromeCustomTabsWebNavigator.java:40)
at net.nextbike.v3.presentation.ui.main.view.MainActivity.showForMenuItem(MainActivity.java:305)
at net.nextbike.v3.presentation.ui.main.presenter.MainPresenter.onCustomMenuItemClicked(MainPresenter.java:121)
at net.nextbike.v3.presentation.ui.main.view.MainActivity.onNavigationItemSelected(MainActivity.java:135)
at android.support.design.widget.NavigationView$1.onMenuItemSelected(NavigationView.java:156)
at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:817)
at android.support.v7.view.menu.SubMenuBuilder.dispatchMenuItemSelected(SubMenuBuilder.java:89)
at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:156)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:964)
at android.support.design.internal.NavigationMenuPresenter$1.onClick(NavigationMenuPresenter.java:332)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

The stack trace claims that there seems to be no method ActivityCompat.startActivity(X). So when I look into the docs[1] it seems to be true.

  1. ActivityCompat Documentation

EasyCustomTabsIntentBuilder always requires a connection

Users might not want to open a connection, but only theme the tab.
Make it optional and use CustomTabsIntent.Builder () when EasyCustomTabsIntentBuilder.useSameBrowser was not called.

Or should it be useSameTab ? Needs better understanding of the different constructors.

Implement ease custom action - SHARE

One of the actions that would be most likely included in a chrome custom tab is the SHARE action. Is it worth to help developers to include a facility for it? Probably yes.

no java-rx

It would be nice, that the developer using you library is not forced to use RX if you just use it internally.

Weird behavior on back/close pressed

Hi all and thank you for the useful library.

I'm seeing a weird behavior when I try to go back to the app from the CustomTab. When I tap back or the X symbol, the CustomTab goes back for a moment to my app and then it jumps to Chrome. This is not happening if there is no Chrome instance in the recent apps.

My Activity contains this configuration:

    val fallback = NavigationFallback { url ->
        Toast.makeText(applicationContext, "CustomTabs not supported", Toast.LENGTH_SHORT).show()
        val intent = Intent(Intent.ACTION_VIEW).setData(url).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        startActivity(intent)
    }
    val customizer = IntentCustomizer { simpleChromeCustomTabsIntentBuilder ->
        val icon = BitmapFactory.decodeResource(resources, android.R.drawable.ic_menu_share)
        val shareLabel = getString(R.string.share_menu_item)
        val actionIntent = Intent(this.applicationContext, ShareBroadcastReceiver::class.java)
        val pendingIntent = PendingIntent.getBroadcast(applicationContext, 0, actionIntent, 0);

        simpleChromeCustomTabsIntentBuilder
            .withUrlBarHiding()
            .withDefaultShareMenuItem()
            .withToolbarColor(ContextCompat.getColor(this, R.color.primary))
            .withActionButton(icon, shareLabel, pendingIntent, false)
    }
    override fun openUrl(url: Uri) {
        SimpleChromeCustomTabs.getInstance()
            .withFallback(fallback)
            .withIntentCustomizer(customizer)
            .navigateTo(url, this)
    }

Am I missing something? Thank you.

Missing a Callback on SimpleChromeCustomTabs.connectTo(Activity activity)

Even if SimpleChromeCustomTabs allows to set a navigation fallback if something goes wrong, it should also include a way to notify that the connection failed when SimpleChromeCustomTabs,connectTo(Activity activity) is called. This provides the client with an early feedback of any potential problems.

Allow browser selection.

Related to good practices on applications using chrome custom tabs we found two that are particularly interested, but not easy to achieve with SimpleChromeCustomTabs.

  • Allow the user to disable Chrome custom tabs.
  • Allow the user to select the browser to be used when navigating with Chrome custom tabs.

The reasoning for the first one is obvious, some users want to navigate with the browsers, and some of them could be really used to that. Let's respect them.

The reasoning for the second one it seems that in the future more browsers will have support for Chrome custom tabs, and would be cool to let the user decide which one to use.

The library should include facilities to achieve the two practices described.

Include example of navigation using Linkify

It is very likely that developers want to make use of Linkify delegating navigation to a Chrome custom tab. What about providing a nice example in the demo about how to achieve this?

Causes RunTimeException

Stacktrace:

Fatal Exception: java.lang.RuntimeException: Unable to pause activity {net.nextbike.serviceapp/net.nextbike.serviceapp.menu.view.MenuActivity}: java.lang.IllegalArgumentException: Service not registered: com.novoda.simplechromecustomtabs.connection.Binder$ServiceConnection@16dee566
       at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3693)
       at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3652)
       at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:3627)
       at android.app.ActivityThread.access$1100(ActivityThread.java:177)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1443)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:135)
       at android.app.ActivityThread.main(ActivityThread.java:5912)
       at java.lang.reflect.Method.invoke(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:372)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1405)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1200)
Caused by java.lang.IllegalArgumentException: Service not registered: com.novoda.simplechromecustomtabs.connection.Binder$ServiceConnection@16dee566
       at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1094)
       at android.app.ContextImpl.unbindService(ContextImpl.java:2000)
       at android.content.ContextWrapper.unbindService(ContextWrapper.java:558)
       at com.novoda.simplechromecustomtabs.connection.Binder.unbindCustomTabsService(Binder.java:57)
       at com.novoda.simplechromecustomtabs.connection.SimpleChromeCustomTabsConnection.disconnectFrom(SimpleChromeCustomTabsConnection.java:67)
       at com.novoda.simplechromecustomtabs.SimpleChromeCustomTabs.disconnectFrom(SimpleChromeCustomTabs.java:123)
       at net.nextbike.serviceapp.base.BaseActivity.onPause(BaseActivity.java:84)
       at net.nextbike.serviceapp.base.LocationAwareActivity.onPause_aroundBody2(LocationAwareActivity.java:60)
       at net.nextbike.serviceapp.base.LocationAwareActivity$AjcClosure3.run(LocationAwareActivity.java:1)
       at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:149)
       at hugo.weaving.internal.Hugo.logAndExecute(Hugo.java:39)
       at net.nextbike.serviceapp.base.LocationAwareActivity.onPause(LocationAwareActivity.java:57)
       at android.app.Activity.performPause(Activity.java:6343)
       at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1322)
       at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3679)
       at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3652)
       at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:3627)
       at android.app.ActivityThread.access$1100(ActivityThread.java:177)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1443)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:135)
       at android.app.ActivityThread.main(ActivityThread.java:5912)
       at java.lang.reflect.Method.invoke(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:372)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1405)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1200)

Statistics:
83 % Samsung
17 % Sony

75 % Android 5
25 % Android 4

The methods in BaseActivity are:

   @Override
    protected void onResume() {
        super.onResume();
        SimpleChromeCustomTabs.getInstance().connectTo(this);

    }

    @Override
    protected void onPause() {
        SimpleChromeCustomTabs.getInstance().disconnectFrom(this);
        super.onPause();
    }

Consider fallback for connectivity issues

It would be super useful to have a fallback for any connectivity issues. An example would be to prevent navigation to chrome custom tabs and keep the user in the app to display a nice message stating they need to check their connectivity.

simpleChromeCustomTabs
                .withFallback(
                        new NavigationFallback() {
                            @Override
                            public void onFallbackNavigateTo(Uri url) {
                                openWebUri(uri);
                            }
                        }
                )
                .withIntentCustomizer(customIntent())
                .navigateTo(uri, activity);
        simpleChromeCustomTabs
                .withFallback(
                        new NavigationFallback() {
                            @Override
                            public void onFallbackNavigateTo(Uri url) {
                                openWebUri(uri);
                            }
                        }
                )
                .withConnectivityFallback(new ConnectivityFallback())
                .withIntentCustomizer(customIntent())
                .navigateTo(uri, activity);

Do it NAO! ๐Ÿ‘…

Wrong action value when using androidx

Similar issue here openid/AppAuth-Android#395

It seems that the CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION value is being wrongly transformed into androidx.browser.customtabs.action.CustomTabsService by the android jetify tooling.

This means the library never considers the connection to be connected

We may want to consider hardcoding the correct value

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.