G'day,
免责声明:我不是 Android 开发人员,我正在对我所描述的问题进行质量检查。我用来描述这个问题的技术术语可能是错误的。
我正在测试一个 Android 应用程序,该应用程序在其清单中描述它可以使用 type 的地址处理 Web 意图https://www.example.com/app/(.*)
。它应该处理这些 URL 的方式是获取第一个匹配组$1
并向https://api.example.com/$1
如果响应是 HTTP200,它会在应用程序内呈现响应。如果没有,它应该在用户设备上安装的任何浏览器应用程序中打开 URL(通过发送打开 URL 的意图)。如果用户的设备上没有安装浏览器应用程序,我们会显示错误提示,指出他们没有安装可以处理此 URL 的浏览器。
现在,这工作正常,除非用户将此应用程序标记为默认处理 URL,例如https://www.example.com/app/(.*)
当它第一次尝试打开像这样的 URL 时https://www.example.com/app/(.*)
。然后,即使用户的系统上安装了浏览器应用程序,当他们打开需要在浏览器中打开的链接时,唯一的选择似乎是我们原来的应用程序,我们必须显示错误消息(看起来像就像系统上没有安装其他可以处理此 URL 的浏览器应用程序一样)。
解决这个问题的一种方法是,当我们遇到需要在浏览器应用程序中打开的 URL 但唯一的选择是我们自己的应用程序时,显示一条消息,要求用户清除此应用程序的默认设置 - 但这是糟糕的用户体验。对于这个问题还有其他解决方法吗?
用于理解问题的示例代码:https://gist.github.com/GVRV/5879fcf0b1838b495e3a2151449e0da3 https://gist.github.com/GVRV/5879fcf0b1838b495e3a2151449e0da3
编辑1:添加示例代码链接
要解决此问题并保持系统对意图的默认处理,您需要 2 个额外的活动和 1 个<activity-alias>
:
-
创建一个新的不可见的空活动。我将其称为 IntentFilterDelegationActivity。此活动负责从以下位置接收 URL 意图activity-alias
(在下一步中定义)。显现:
<activity
android:name=".intent_filter.IntentFilterDelegationActivity"
android:excludeFromRecents="true"
android:exported="true"
android:launchMode="singleInstance"
android:noHistory="true"
android:taskAffinity=""
android:theme="@style/Theme.Transparent"/>
Code:
public class IntentFilterDelegationActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
findAndStartMatchingActivity(getIntent());
finish();
}
}
-
创建一个<activity-alias>
。活动别名负责将您的 URL 意图委托给您的IntentFilterDelegationActivity
。只需要一个清单条目:
<activity-alias
android:name="${packageName}.IntentFilterDelegation"
android:enabled="true"
android:exported="true"
android:targetActivity=".intent_filter.IntentFilterDelegationActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http" android:host="www.example.com"/>
</intent-filter>
</activity-alias>
-
现在您可以做到这一点:您可以停用activity-alias
在启动您自己的 URL 意图之前并在启动后激活别名。这会导致 android 您的应用程序不会被列为可以处理 URL 意图的应用程序。要实现激活和停用,您需要一个额外的活动。我叫它ForceOpenInBrowserActivity
。
显现:
<activity
android:name=".activity.ForceOpenInBrowserActivity"
android:excludeFromRecents="true"
android:launchMode="singleInstance"
android:noHistory="true"
android:taskAffinity=""
android:theme="@style/Theme.Transparent"/>
Code:
public class ForceOpenInBrowserActivity extends Activity
{
public static final String URI = IntentUtils.getIntentExtraString(ForceOpenInBrowserActivity.class, "URI");
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Uri uri = fetchUriFromIntent();
if (uri != null)
{
startForcedBrowserActivity(uri);
}
else
{
finish();
}
}
@Nullable
private Uri fetchUriFromIntent()
{
Uri uri = null;
Intent intent = getIntent();
if (intent != null)
{
uri = intent.getParcelableExtra(URI);
}
return uri;
}
private void startForcedBrowserActivity(Uri uri)
{
disableActivityAlias(this);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// After starting another activity, this activity will be destroyed
// android:noHistory="true" android:excludeFromRecents="true"
startActivity(intent);
}
/**
* Re-enable intent filters when returning to app.
* Note: The intent filters will also be enabled when starting the app.
*/
@Override
protected void onStop()
{
super.onStop();
enableActivityAlias();
}
public void disableActivityAlias()
{
String packageName = getPackageName();
ComponentName componentName = new ComponentName(packageName, packageName + ".IntentFilterDelegation"); // Activity alias
getPackageManager().setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}
public void enableActivityAlias()
{
String packageName = getPackageName();
ComponentName componentName = new ComponentName(packageName, packageName + ".IntentFilterDelegation");
getPackageManager().setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
}
-
现在您可以将任何必须在外部浏览器中打开的 URL 意图发送到ForceOpenInBrowserActivity
:
@NonNull
public static Intent createForceBrowserIntent(Context context, @NonNull Uri uri)
{
Intent intent = new Intent(context, ForceOpenInBrowserActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(ForceOpenInBrowserActivity.URI, uri);
return intent;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)