0

我在执行回退镀铬自定义选项卡的Android浏览器自定义选项卡后备

我指的是几个环节 it has some定制后备实现。我没有明白为什么这是必需的。

我做了以下处理备用,并工作正常。

try { 
     CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); 
     builder.setToolbarColor(ContextCompat.getColor(context, R.color.appthemecolor)); 
     CustomTabsIntent customTabsIntent = builder.build(); 
     customTabsIntent.launchUrl(context, Uri.parse(url)); 
    } catch (ActivityNotFoundException e) { 
     e.printStackTrace(); 
     Intent intent = new Intent(context, WebviewActivity.class); 
     intent.putExtra(WebviewActivity.EXTRA_URL, url); 
     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 
     context.startActivity(intent); 
    } 

任何想法为什么需要这种复杂的实现来处理回退?

使用支持库compile 'com.android.support:customtabs:25.3.1'

回答

2

的以下版本如果您通过CustomTabsIntent源代码中看到的,它无非只是一个辅助创建一个普通的隐含意图使用Intent.ACTION_VIEW打开URL等等。它可以帮助您使用Chrome识别的特定键为意图添加额外数据,Chrome随后将使用该键来呈现自定义用户界面。

这里是the official page的解释:

自定义选项卡使用与关键额外的ACTION_VIEW意向来定制 的UI。这意味着默认情况下,页面将在系统 浏览器或用户的默认浏览器中打开。

如果用户安装了Chrome并且它是默认浏览器,它将自动选取EXTRAS并呈现自定义UI。它 也可以让另一个浏览器使用Intent extras来为 提供一个类似的定制界面。

对于链接上的解决方案,源代码取自here。正如您从CustomTabActivityHelper#openCustomTab可以看到的,首先它会查找支持自定义选项卡的应用程序。如果可用,则启动CustomTabsIntent所述的隐含意图。如果没有,请打开WebViewActivity

如何找出是否有任何应用程序支持自定义选项卡?你可以选择CustomTabsHelper.getPackageNameToUse。首先,它会解析所有可以使用Intent.ACTION_VIEW打开URL的应用程序。然后,它会检查该应用是否支持自定义标签。

然后,

  • 如果没有应用程序可用,则返回null
  • 如果只有1个可用的应用程序,将其返回。
  • 如果超过1个应用程序可用,其中1个是默认应用程序,请将其返回。
  • 如果有超过1个应用可用,其中1个是Chrome,请将其退回。
  • 否则,返回null
  • (如果超过1级可用的应用程序,你可以把一个逻辑来要求用户选择他们想要的任何浏览器)

现在,如何您的解决方案?

如果我们使用您的解决方案,WebviewActivity将被打开,如果没有应用程序可以处理CustomTabsIntent创建的隐式意图,在这种情况下,没有安装浏览器?如果我们有浏览器,而且它们都不支持自定义选项卡,会发生什么情况?您的应用仍然会要求在浏览器中打开链接,而不是在WebViewActivity中。

请记住,CustomTabsIntent只是一个帮手,用于创建一个普通的隐式意图打开一个URL使用Intent.ACTION_VIEW与各种EXTRA数据来定制的用户界面。如何自定义UI由浏览器处理。基本上,我认为我们可以创建并开始使用自定义用户界面来打开浏览器,但不需要CustomTabsIntent。我从来没有尝试过这个。

如果你想链接到任何浏览器打开,不管浏览器支持自定义选项卡或没有,该链接将在WebViewActivity打开,如果没有可用的应用程序,您的解决方案解决它,即使它是不是我想的最好的解决方案。

但是,如果你希望链接在浏览器,支持自定义选项卡被打开,并且链接到WebViewActivity如果没有应用程序,支持自定义选项卡提供被打开,他的解决办法是正确的。

但是,如果你想要的只是提供回退机制,它不应该那么复杂。这里是更简单的代码:

public class CustomTabs { 

    private static final String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService"; 

    private static final String STABLE_PACKAGE = "com.android.chrome"; 
    private static final String BETA_PACKAGE = "com.chrome.beta"; 
    private static final String DEV_PACKAGE = "com.chrome.dev"; 
    private static final String LOCAL_PACKAGE = "com.google.android.apps.chrome"; 

    public static void openTab(Context context, String url) { 
     CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); 

     /* do some UI customization here */ 

     CustomTabsIntent customTabsIntent = builder.build(); 

     String packageName = getPackageNameToUse(context); 

     if (packageName == null) { 
      Intent intent = new Intent(context, WebviewActivity.class); 
      intent.putExtra(WebviewActivity.EXTRA_URL, url); 
      intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 

      context.startActivity(intent); 
     } else { 
      customTabsIntent.intent.setPackage(packageName); 
      customTabsIntent.launchUrl(context, Uri.parse(url)); 
     } 
    } 

    private static String getPackageNameToUse(Context context) { 
     String packageNameToUse = null; 

     PackageManager pm = context.getPackageManager(); 

     Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com")); 

     ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0); 

     String defaultViewHandlerPackageName = null; 
     if (defaultViewHandlerInfo != null) { 
      defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName; 
     } 

     List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(activityIntent, 0); 

     List<String> packagesSupportingCustomTabs = new ArrayList<>(); 
     for (ResolveInfo info : resolvedActivityList) { 
      Intent serviceIntent = new Intent(); 
      serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION); 
      serviceIntent.setPackage(info.activityInfo.packageName); 
      if (pm.resolveService(serviceIntent, 0) != null) { 
       packagesSupportingCustomTabs.add(info.activityInfo.packageName); 
      } 
     } 

     if (packagesSupportingCustomTabs.isEmpty()) { 
      packageNameToUse = null; 
     } else if (packagesSupportingCustomTabs.size() == 1) { 
      packageNameToUse = packagesSupportingCustomTabs.get(0); 
     } else if (!TextUtils.isEmpty(defaultViewHandlerPackageName) 
       && !hasSpecializedHandlerIntents(context, activityIntent) 
       && packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) { 
      packageNameToUse = defaultViewHandlerPackageName; 
     } else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) { 
      packageNameToUse = STABLE_PACKAGE; 
     } else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) { 
      packageNameToUse = BETA_PACKAGE; 
     } else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) { 
      packageNameToUse = DEV_PACKAGE; 
     } else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) { 
      packageNameToUse = LOCAL_PACKAGE; 
     } 
     return packageNameToUse; 
    } 

    private static boolean hasSpecializedHandlerIntents(Context context, Intent intent) { 
     try { 
      PackageManager pm = context.getPackageManager(); 
      List<ResolveInfo> handlers = pm.queryIntentActivities(intent, PackageManager.GET_RESOLVED_FILTER); 

      if (handlers == null || handlers.size() == 0) { 
       return false; 
      } 

      for (ResolveInfo resolveInfo : handlers) { 
       IntentFilter filter = resolveInfo.filter; 
       if (filter == null) continue; 
       if (filter.countDataAuthorities() == 0 || filter.countDataPaths() == 0) continue; 
       if (resolveInfo.activityInfo == null) continue; 
       return true; 
      } 

     } catch (RuntimeException e) { 
      Log.e("LOG", "Runtime exception while getting specialized handlers"); 
     } 

     return false; 
    } 
} 
+0

嗨,感谢这篇文章!但是LOCAL_PACKAGE和STABLE_PACKAGE有什么区别?为什么你允许用户在这里使用LOCAL_PACKAGE? –

+0

@JiechaoWang说实话,我不知道。代码来自Chrome团队提供的示例代码。 'STABLE_PACKAGE'很明显。这是我们通常使用的标准版Chrome。对于'LOCAL_PACKAGE',从包名称来看,我认为这是系统附带的应用程序。 – marcelljee

相关问题