|
1 | 1 | package com.reactnativewebbrowser |
2 | 2 |
|
3 | | -import com.facebook.react.bridge.Promise |
4 | | -import com.facebook.react.bridge.ReactApplicationContext |
5 | | -import com.facebook.react.bridge.ReactContextBaseJavaModule |
6 | | -import com.facebook.react.bridge.ReactMethod |
| 3 | +import android.content.Intent |
| 4 | +import android.graphics.Color |
| 5 | +import android.net.Uri |
| 6 | +import android.os.Bundle |
| 7 | +import android.text.TextUtils |
| 8 | +import androidx.browser.customtabs.CustomTabsIntent |
| 9 | +import com.facebook.react.bridge.* |
| 10 | +import com.reactnativewebbrowser.error.CurrentActivityNotFoundException |
| 11 | +import com.reactnativewebbrowser.error.NoPreferredPackageFound |
| 12 | +import com.reactnativewebbrowser.error.PackageManagerNotFoundException |
7 | 13 |
|
8 | 14 | class NativeWebBrowserModule(reactContext: ReactApplicationContext) : |
9 | 15 | ReactContextBaseJavaModule(reactContext) { |
10 | 16 |
|
11 | 17 | val activityProvider = InternalActicityProvider(reactContext) |
12 | | - val customTabsActivitiesHelper = InternalCustomTabsActivitiesHelper(activityProvider) |
13 | | - val customTabsConnectionHelper = InternalCustomTabsConnectionHelper(reactContext) |
| 18 | + val customTabsActivitiesHelper = |
| 19 | + InternalCustomTabsActivitiesHelper(activityProvider) |
| 20 | + val customTabsConnectionHelper = |
| 21 | + InternalCustomTabsConnectionHelper(reactContext) |
14 | 22 |
|
15 | 23 | private val BROWSER_PACKAGE_KEY = "browserPackage" |
16 | 24 | private val SERVICE_PACKAGE_KEY = "servicePackage" |
@@ -45,5 +53,225 @@ class NativeWebBrowserModule(reactContext: ReactApplicationContext) : |
45 | 53 |
|
46 | 54 | } |
47 | 55 |
|
| 56 | + @ExpoMethod |
| 57 | + fun warmUpAsync(packageName: String?, promise: Promise) { |
| 58 | + try { |
| 59 | + val packageName = givenOrPreferredPackageName(packageName) |
| 60 | + customTabsConnectionHelper.warmUp(packageName) |
| 61 | + val result = Bundle() |
| 62 | + result.putString( |
| 63 | + expo.modules.webbrowser.WebBrowserModule.SERVICE_PACKAGE_KEY, |
| 64 | + packageName |
| 65 | + ) |
| 66 | + promise.resolve(result) |
| 67 | + } catch (ex: NoPreferredPackageFound) { |
| 68 | + promise.reject(ex) |
| 69 | + } |
| 70 | + } |
| 71 | + |
| 72 | + @ExpoMethod |
| 73 | + fun coolDownAsync(packageName: String?, promise: Promise) { |
| 74 | + var packageName = packageName |
| 75 | + try { |
| 76 | + packageName = givenOrPreferredPackageName(packageName) |
| 77 | + if (mConnectionHelper.coolDown(packageName)) { |
| 78 | + val result = Bundle() |
| 79 | + result.putString( |
| 80 | + expo.modules.webbrowser.WebBrowserModule.SERVICE_PACKAGE_KEY, |
| 81 | + packageName |
| 82 | + ) |
| 83 | + promise.resolve(result) |
| 84 | + } else { |
| 85 | + promise.resolve(Bundle()) |
| 86 | + } |
| 87 | + } catch (ex: NoPreferredPackageFound) { |
| 88 | + promise.reject(ex) |
| 89 | + } |
| 90 | + } |
| 91 | + |
| 92 | + @ExpoMethod |
| 93 | + fun mayInitWithUrlAsync( |
| 94 | + url: String?, |
| 95 | + packageName: String?, |
| 96 | + promise: Promise |
| 97 | + ) { |
| 98 | + var packageName = packageName |
| 99 | + try { |
| 100 | + packageName = givenOrPreferredPackageName(packageName) |
| 101 | + mConnectionHelper.mayInitWithUrl(packageName, Uri.parse(url)) |
| 102 | + val result = Bundle() |
| 103 | + result.putString( |
| 104 | + expo.modules.webbrowser.WebBrowserModule.SERVICE_PACKAGE_KEY, |
| 105 | + packageName |
| 106 | + ) |
| 107 | + promise.resolve(result) |
| 108 | + } catch (ex: NoPreferredPackageFound) { |
| 109 | + promise.reject(ex) |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | + @ExpoMethod |
| 114 | + fun getCustomTabsSupportingBrowsersAsync(promise: Promise) { |
| 115 | + try { |
| 116 | + val activities: ArrayList<String> = |
| 117 | + mCustomTabsResolver.getCustomTabsResolvingActivities() |
| 118 | + val services: ArrayList<String> = |
| 119 | + mCustomTabsResolver.getCustomTabsResolvingServices() |
| 120 | + val preferredPackage: String = |
| 121 | + mCustomTabsResolver.getPreferredCustomTabsResolvingActivity(activities) |
| 122 | + val defaultPackage: String = |
| 123 | + mCustomTabsResolver.getDefaultCustomTabsResolvingActivity() |
| 124 | + var defaultCustomTabsPackage: String? = null |
| 125 | + if (activities.contains(defaultPackage)) { // It might happen, that default activity does not support Chrome Tabs. Then it will be ResolvingActivity and we don't want to return it as a result. |
| 126 | + defaultCustomTabsPackage = defaultPackage |
| 127 | + } |
| 128 | + val result = Bundle() |
| 129 | + result.putStringArrayList( |
| 130 | + expo.modules.webbrowser.WebBrowserModule.BROWSER_PACKAGES_KEY, |
| 131 | + activities |
| 132 | + ) |
| 133 | + result.putStringArrayList( |
| 134 | + expo.modules.webbrowser.WebBrowserModule.SERVICE_PACKAGES_KEY, |
| 135 | + services |
| 136 | + ) |
| 137 | + result.putString( |
| 138 | + expo.modules.webbrowser.WebBrowserModule.PREFERRED_BROWSER_PACKAGE, |
| 139 | + preferredPackage |
| 140 | + ) |
| 141 | + result.putString( |
| 142 | + expo.modules.webbrowser.WebBrowserModule.DEFAULT_BROWSER_PACKAGE, |
| 143 | + defaultCustomTabsPackage |
| 144 | + ) |
| 145 | + promise.resolve(result) |
| 146 | + } catch (ex: CurrentActivityNotFoundException) { |
| 147 | + promise.reject(ex) |
| 148 | + } catch (ex: PackageManagerNotFoundException) { |
| 149 | + promise.reject(ex) |
| 150 | + } |
| 151 | + } |
| 152 | + |
| 153 | + /** |
| 154 | + * @param url Url to be opened by WebBrowser |
| 155 | + * @param arguments Required arguments are: |
| 156 | + * toolbarColor: String; |
| 157 | + * browserPackage: String; |
| 158 | + * enableBarCollapsing: Boolean; |
| 159 | + * showTitle: Boolean; |
| 160 | + * enableDefaultShareMenuItem: Boolean; |
| 161 | + * showInRecents: Boolean; |
| 162 | + * @param promise |
| 163 | + */ |
| 164 | + @ExpoMethod |
| 165 | + fun openBrowserAsync( |
| 166 | + url: String?, |
| 167 | + arguments: ReadableArguments, |
| 168 | + promise: Promise |
| 169 | + ) { |
| 170 | + val intent = createCustomTabsIntent(arguments) |
| 171 | + intent.data = Uri.parse(url) |
| 172 | + try { |
| 173 | + if (mCustomTabsResolver.canResolveIntent(intent)) { |
| 174 | + mCustomTabsResolver.startCustomTabs(intent) |
| 175 | + val result = Bundle() |
| 176 | + result.putString("type", "opened") |
| 177 | + promise.resolve(result) |
| 178 | + } else { |
| 179 | + promise.reject( |
| 180 | + expo.modules.webbrowser.WebBrowserModule.ERROR_CODE, |
| 181 | + "No matching activity!" |
| 182 | + ) |
| 183 | + } |
| 184 | + } catch (ex: CurrentActivityNotFoundException) { |
| 185 | + promise.reject(ex) |
| 186 | + } catch (ex: PackageManagerNotFoundException) { |
| 187 | + promise.reject(ex) |
| 188 | + } |
| 189 | + } |
| 190 | + |
| 191 | + private fun createCustomTabsIntent(arguments: ReadableMap): Intent { |
| 192 | + val builder = CustomTabsIntent.Builder() |
| 193 | + val color: String? = |
| 194 | + arguments.getString(TOOLBAR_COLOR_KEY) |
| 195 | + val secondaryColor: String? = |
| 196 | + arguments.getString(SECONDARY_TOOLBAR_COLOR_KEY) |
| 197 | + val packageName: String? = |
| 198 | + arguments.getString(BROWSER_PACKAGE_KEY) |
| 199 | + try { |
| 200 | + if (!TextUtils.isEmpty(color)) { |
| 201 | + val intColor = Color.parseColor(color) |
| 202 | + builder.setToolbarColor(intColor) |
| 203 | + } |
| 204 | + if (!TextUtils.isEmpty(secondaryColor)) { |
| 205 | + val intSecondaryColor = Color.parseColor(secondaryColor) |
| 206 | + builder.setSecondaryToolbarColor(intSecondaryColor) |
| 207 | + } |
| 208 | + } catch (ignored: IllegalArgumentException) { |
| 209 | + } |
| 210 | + builder.setShowTitle( |
| 211 | + if (!arguments.hasKey(SHOW_TITLE_KEY) || arguments.isNull(SHOW_TITLE_KEY)) { |
| 212 | + false |
| 213 | + } else { |
| 214 | + arguments.getBoolean( |
| 215 | + SHOW_TITLE_KEY |
| 216 | + ) |
| 217 | + } |
| 218 | + ) |
| 219 | + if (arguments.hasKey(DEFAULT_SHARE_MENU_ITEM) && arguments.getBoolean( |
| 220 | + DEFAULT_SHARE_MENU_ITEM |
| 221 | + ) |
| 222 | + ) { |
| 223 | + builder.addDefaultShareMenuItem() |
| 224 | + } |
| 225 | + val intent = builder.build().intent |
| 226 | + |
| 227 | + // We cannot use builder's method enableUrlBarHiding, because there is no corresponding disable method and some browsers enables it by default. |
| 228 | + intent.putExtra( |
| 229 | + CustomTabsIntent.EXTRA_ENABLE_URLBAR_HIDING, |
| 230 | + arguments.getBoolean( |
| 231 | + ENABLE_BAR_COLLAPSING_KEY, |
| 232 | + false |
| 233 | + ) |
| 234 | + ) |
| 235 | + if (!TextUtils.isEmpty(packageName)) { |
| 236 | + intent.setPackage(packageName) |
| 237 | + } |
| 238 | + if (arguments.getBoolean( |
| 239 | + CREATE_TASK, |
| 240 | + true |
| 241 | + ) |
| 242 | + ) { |
| 243 | + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) |
| 244 | + if (!arguments.getBoolean( |
| 245 | + SHOW_IN_RECENTS, |
| 246 | + false |
| 247 | + ) |
| 248 | + ) { |
| 249 | + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) |
| 250 | + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) |
| 251 | + } |
| 252 | + } |
| 253 | + return intent |
| 254 | + } |
| 255 | + |
| 256 | + private fun givenOrPreferredPackageName(packageName: String?): String? { |
| 257 | + var processedPackageName = packageName |
| 258 | + try { |
| 259 | + if (TextUtils.isEmpty(processedPackageName)) { |
| 260 | + processedPackageName = |
| 261 | + customTabsActivitiesHelper.getPreferredCustomTabsResolvingActivity( |
| 262 | + null |
| 263 | + ) |
| 264 | + } |
| 265 | + } catch (ex: CurrentActivityNotFoundException) { |
| 266 | + throw NoPreferredPackageFound(NO_PREFERRED_PACKAGE_MSG) |
| 267 | + } catch (ex: PackageManagerNotFoundException) { |
| 268 | + throw NoPreferredPackageFound(NO_PREFERRED_PACKAGE_MSG) |
| 269 | + } |
| 270 | + if (TextUtils.isEmpty(processedPackageName)) { |
| 271 | + throw NoPreferredPackageFound(NO_PREFERRED_PACKAGE_MSG) |
| 272 | + } |
| 273 | + return processedPackageName |
| 274 | + } |
| 275 | + |
48 | 276 |
|
49 | 277 | } |
0 commit comments