在 Android 中查看针对浏览器与外部应用程序的意图
View intents meant for browser vs external app in Android
我正在使用 android webview 组件构建一个基本的网络浏览器,并且最近添加了对在相关外部应用程序中打开 links 的支持,例如如果您在一个页面上并单击一个 youtube link,则会打开 youtube 应用程序而不是导航到网页。
当应用程序是新安装的并且您第一次点击 link 时(我怀疑我的应用程序此时不是默认浏览器),这可以很好地接受。然后它总是提示你是否想在另一个应用程序中打开它,即使唯一的其他相关应用程序是其他浏览器,这不是一个很好的用户体验,因为用户已经在他们想要打开的浏览器中 link 否则他们不会使用它。
所以我需要能够区分 link 有一个专门安装的应用程序(例如,它找到了维基百科 links 的维基百科应用程序)和 link没有专门的应用程序,适合任何浏览器打开。
这是MyWebViewClient.shouldOverrideUrlLoading()
中的相关代码...
Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
if(intent!=null){
PackageManager packageManager = context.getPackageManager();
ResolveInfo info = packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (info != null) {
String suggestedPackageName = info.activityInfo.applicationInfo.packageName;
String intentAction = intent.getAction();
final boolean packageMatchesThisBrowser = (MY_PACKAGE_NAME).equals(suggestedPackageName);
final boolean isUrlAttempt = UrlHelper.isUrlAttempt(url);
final boolean areSuggestedAppsOnlyBrowsers = false; // ????
final boolean canItBeOpenedInThisBrowser = isUrlAttempt;
if(canItBeOpenedInThisBrowser && (packageMatchesThisBrowser || areSuggestedAppsOnlyBrowsers)){
return false; // allow the url to load normally in the current web view
}else {
// Else we have a dedicated app link (e.g. tel://, whatsapp://, intent://) or app supported links like (e.g. https://youtube.com/...)
context.startActivity(intent);
return true; // Launched the activity successfully so block webview from loading
}
} else {
// ...
}
}
我想到了这个,让我知道它是否有效我目前无法测试它。
/**
* Assumes that a browser is identified by having a IntentFilter match all http and https
* protocols without matching either a host or path in the url.
*/
public boolean checkIfOtherBrowser(Context context, ResolveInfo info, Intent intent) {
if (!intent.getScheme().equals("http") || !intent.getScheme().equals("https")) {
return false;
}
IntentFilter filter = info.filter;
if (filter != null) {
int result = filter.match(
context.getContentResolver(),
intent,
true,
"somelogtag"
);
return (result & IntentFilter.MATCH_CATEGORY_SCHEME) > 0 && // Scheme was matched
(result & IntentFilter.MATCH_CATEGORY_HOST) == 0 &&
(result & IntentFilter.MATCH_CATEGORY_PATH) == 0; // But not for a specific host or path
}
return false;
}
使用的研究资源:
- https://github.com/mozilla-mobile/reference-browser/blob/master/app/src/main/AndroidManifest.xml#L108-L114
- https://developer.android.com/reference/android/content/IntentFilter#match(android.content.ContentResolver,%20android.content.Intent,%20boolean,%20java.lang.String)
- https://developer.android.com/training/app-links/deep-linking
感谢 JensV,我想我想出了一个可行的解决方案。至少它似乎能够区分链接专用应用程序(Instagram、维基百科等)与其他浏览器等通用应用程序。
public boolean areResolvedActivitiesOnlyBrowsers(Context context, Intent uriIntent) {
PackageManager packageManager = context.getPackageManager();
List<ResolveInfo> resolvedActivityList;
final String scheme = uriIntent.getScheme();
if (scheme == null || (!scheme.equals("http") && !scheme.equals("https"))) {
return false;
}
// Find all activities that could open the URI intent
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
resolvedActivityList = packageManager.queryIntentActivities(uriIntent, PackageManager.MATCH_ALL);
}else{
resolvedActivityList = packageManager.queryIntentActivities(uriIntent, 0);
}
// Check each activity for a match with the path part of the URI, if
for (ResolveInfo activityResolveInfo : resolvedActivityList) {
final int match = activityResolveInfo.match;
boolean matchesPath = (match & IntentFilter.MATCH_CATEGORY_PATH) > 0;
if(matchesPath){
return false;
}
}
return true;
}
我正在使用 android webview 组件构建一个基本的网络浏览器,并且最近添加了对在相关外部应用程序中打开 links 的支持,例如如果您在一个页面上并单击一个 youtube link,则会打开 youtube 应用程序而不是导航到网页。
当应用程序是新安装的并且您第一次点击 link 时(我怀疑我的应用程序此时不是默认浏览器),这可以很好地接受。然后它总是提示你是否想在另一个应用程序中打开它,即使唯一的其他相关应用程序是其他浏览器,这不是一个很好的用户体验,因为用户已经在他们想要打开的浏览器中 link 否则他们不会使用它。
所以我需要能够区分 link 有一个专门安装的应用程序(例如,它找到了维基百科 links 的维基百科应用程序)和 link没有专门的应用程序,适合任何浏览器打开。
这是MyWebViewClient.shouldOverrideUrlLoading()
中的相关代码...
Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
if(intent!=null){
PackageManager packageManager = context.getPackageManager();
ResolveInfo info = packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (info != null) {
String suggestedPackageName = info.activityInfo.applicationInfo.packageName;
String intentAction = intent.getAction();
final boolean packageMatchesThisBrowser = (MY_PACKAGE_NAME).equals(suggestedPackageName);
final boolean isUrlAttempt = UrlHelper.isUrlAttempt(url);
final boolean areSuggestedAppsOnlyBrowsers = false; // ????
final boolean canItBeOpenedInThisBrowser = isUrlAttempt;
if(canItBeOpenedInThisBrowser && (packageMatchesThisBrowser || areSuggestedAppsOnlyBrowsers)){
return false; // allow the url to load normally in the current web view
}else {
// Else we have a dedicated app link (e.g. tel://, whatsapp://, intent://) or app supported links like (e.g. https://youtube.com/...)
context.startActivity(intent);
return true; // Launched the activity successfully so block webview from loading
}
} else {
// ...
}
}
我想到了这个,让我知道它是否有效我目前无法测试它。
/**
* Assumes that a browser is identified by having a IntentFilter match all http and https
* protocols without matching either a host or path in the url.
*/
public boolean checkIfOtherBrowser(Context context, ResolveInfo info, Intent intent) {
if (!intent.getScheme().equals("http") || !intent.getScheme().equals("https")) {
return false;
}
IntentFilter filter = info.filter;
if (filter != null) {
int result = filter.match(
context.getContentResolver(),
intent,
true,
"somelogtag"
);
return (result & IntentFilter.MATCH_CATEGORY_SCHEME) > 0 && // Scheme was matched
(result & IntentFilter.MATCH_CATEGORY_HOST) == 0 &&
(result & IntentFilter.MATCH_CATEGORY_PATH) == 0; // But not for a specific host or path
}
return false;
}
使用的研究资源:
- https://github.com/mozilla-mobile/reference-browser/blob/master/app/src/main/AndroidManifest.xml#L108-L114
- https://developer.android.com/reference/android/content/IntentFilter#match(android.content.ContentResolver,%20android.content.Intent,%20boolean,%20java.lang.String)
- https://developer.android.com/training/app-links/deep-linking
感谢 JensV,我想我想出了一个可行的解决方案。至少它似乎能够区分链接专用应用程序(Instagram、维基百科等)与其他浏览器等通用应用程序。
public boolean areResolvedActivitiesOnlyBrowsers(Context context, Intent uriIntent) {
PackageManager packageManager = context.getPackageManager();
List<ResolveInfo> resolvedActivityList;
final String scheme = uriIntent.getScheme();
if (scheme == null || (!scheme.equals("http") && !scheme.equals("https"))) {
return false;
}
// Find all activities that could open the URI intent
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
resolvedActivityList = packageManager.queryIntentActivities(uriIntent, PackageManager.MATCH_ALL);
}else{
resolvedActivityList = packageManager.queryIntentActivities(uriIntent, 0);
}
// Check each activity for a match with the path part of the URI, if
for (ResolveInfo activityResolveInfo : resolvedActivityList) {
final int match = activityResolveInfo.match;
boolean matchesPath = (match & IntentFilter.MATCH_CATEGORY_PATH) > 0;
if(matchesPath){
return false;
}
}
return true;
}