├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── saurabharora
│ │ └── customtabs
│ │ └── sample
│ │ ├── MainActivity.kt
│ │ └── ServiceConnectionActivity.kt
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── layout
│ ├── activity_main.xml
│ └── activity_serviceconnection.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── customtabs
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── saurabharora
│ └── customtabs
│ ├── ConnectionCallback.kt
│ ├── CustomTabActivityHelper.kt
│ ├── CustomTabFallback.kt
│ ├── extensions
│ └── CustomTabsIntentExtensions.kt
│ └── internal
│ ├── CustomTabsHelper.kt
│ ├── KeepAliveService.kt
│ ├── ServiceConnection.kt
│ └── ServiceConnectionCallback.kt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | ## OSX ignores
6 | .DS_Store
7 |
8 | # Files for the ART/Dalvik VM
9 | *.dex
10 |
11 | # Java class files
12 | *.class
13 |
14 | # Generated files
15 | bin/
16 | gen/
17 | out/
18 |
19 | # Gradle files
20 | .gradle/
21 | build/
22 |
23 | # Local configuration file (sdk path, etc)
24 | local.properties
25 |
26 | # Proguard folder generated by Eclipse
27 | proguard/
28 |
29 | # Log Files
30 | *.log
31 |
32 | # Android Studio Navigation editor temp files
33 | .navigation/
34 |
35 | # Android Studio captures folder
36 | captures/
37 |
38 | ## IntelliJ ignores
39 | *.iml
40 | .idea/*
41 |
42 | # Keystore files
43 | # Uncomment the following line if you do not want to check your keystore files in.
44 | #*.jks
45 |
46 | # External native build folder generated in Android Studio 2.2 and later
47 | .externalNativeBuild
48 |
49 | # Google Services (e.g. APIs or Firebase)
50 | google-services.json
51 |
52 | # Freeline
53 | freeline.py
54 | freeline/
55 | freeline_project_description.json
56 |
57 | # fastlane
58 | fastlane/report.xml
59 | fastlane/Preview.html
60 | fastlane/screenshots
61 | fastlane/test_output
62 | fastlane/readme.md
63 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Saurabh
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Chrome Custom Tabs - Kotlin and Lifecycle Aware
2 | =================
3 |
4 | This is a rewrite of the helpers offered by [Google](https://github.com/GoogleChrome/custom-tabs-client).
5 |
6 | The ones offered by Google are written in JAVA and require integration with the Activity lifecycle if the user needs to support warmup of the browser for performance gains.
7 |
8 | - This new implementaion uses [Lifecycle](https://developer.android.com/reference/androidx/lifecycle/Lifecycle) to hide away the service binding logic.
9 | - Rewritting in Kotlin makes the code consixe and offers a cleaner and easier to work with API, espcially with the support of optional paramters.
10 |
11 |
12 | Usage
13 | -------
14 | Add a dependency to your `build.gradle`:
15 |
16 | dependencies {
17 | implementation 'com.saurabharora.customtabs:customtabs:1.1'
18 | }
19 |
20 | Now in your Activity/Fragment from where you want to launch the Chrome Custom Tabs:
21 |
22 | private val customTabActivityHelper: CustomTabActivityHelper =
23 | CustomTabActivityHelper(context = this, lifecycle = lifecycle, connectionCallback = this)
24 |
25 | //If you know the potential URL that will be loaded:
26 | customTabActivityHelper.mayLaunchUrl(uri)
27 |
28 | val customTabsIntent = CustomTabsIntent.Builder(customTabActivityHelper.session)
29 | .build()
30 |
31 | customTabsIntent.launchWithFallback(activity = this, uri = uri)
32 |
33 | See the demo app for more details.
34 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 |
4 | android {
5 | compileSdkVersion 28
6 | defaultConfig {
7 | applicationId "com.saurabharora.customtabs.sample"
8 | minSdkVersion 15
9 | targetSdkVersion 28
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | implementation fileTree(include: ['*.jar'], dir: 'libs')
24 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
25 | implementation 'androidx.appcompat:appcompat:1.0.0-rc01'
26 | testImplementation 'junit:junit:4.12'
27 | implementation project(':customtabs')
28 | }
29 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saurabharora/customtabs/sample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.saurabharora.customtabs.sample
2 |
3 | import android.content.Intent
4 | import android.net.Uri
5 | import androidx.appcompat.app.AppCompatActivity
6 | import android.os.Bundle
7 | import android.widget.TextView
8 | import androidx.browser.customtabs.CustomTabsIntent
9 | import com.saurabharora.customtabs.extensions.launchWithFallback
10 |
11 |
12 | class MainActivity : AppCompatActivity() {
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | setContentView(R.layout.activity_main)
17 |
18 | val tvNormal = findViewById(R.id.tvNormal)
19 | val tvServiceConnection = findViewById(R.id.tvServiceConnection)
20 |
21 | tvNormal.setOnClickListener {
22 | val customTabsIntent = CustomTabsIntent.Builder().build()
23 | customTabsIntent.launchWithFallback(this, Uri.parse(getString(R.string.default_test_url)))
24 | }
25 |
26 | tvServiceConnection.setOnClickListener {
27 | startActivity(Intent(this, ServiceConnectionActivity::class.java))
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saurabharora/customtabs/sample/ServiceConnectionActivity.kt:
--------------------------------------------------------------------------------
1 | package com.saurabharora.customtabs.sample
2 |
3 | import android.net.Uri
4 | import com.saurabharora.customtabs.CustomTabActivityHelper
5 | import androidx.browser.customtabs.CustomTabsIntent
6 | import android.widget.EditText
7 | import android.os.Bundle
8 | import android.view.View
9 | import android.widget.Button
10 | import androidx.appcompat.app.AppCompatActivity
11 | import com.saurabharora.customtabs.ConnectionCallback
12 | import com.saurabharora.customtabs.extensions.launchWithFallback
13 |
14 |
15 | /**
16 | * This Activity connect to the Chrome Custom Tabs Service on startup, and allows you to decide
17 | * when to call mayLaunchUrl.
18 | */
19 | class ServiceConnectionActivity : AppCompatActivity(), View.OnClickListener, ConnectionCallback {
20 |
21 | private lateinit var urlEditText: EditText
22 | private lateinit var mayLaunchUrlButton: View
23 |
24 | private val customTabActivityHelper: CustomTabActivityHelper =
25 | CustomTabActivityHelper(this, lifecycle, this)
26 |
27 | override fun onCreate(savedInstanceState: Bundle?) {
28 | super.onCreate(savedInstanceState)
29 | setContentView(R.layout.activity_serviceconnection)
30 |
31 | urlEditText = findViewById(R.id.url)
32 | mayLaunchUrlButton = findViewById(R.id.button_may_launch_url)
33 | mayLaunchUrlButton.isEnabled = false
34 | mayLaunchUrlButton.setOnClickListener(this)
35 |
36 | findViewById