5

我需要使用意图过滤器指定我的登录活动:

    <activity
        android:name=".view.LoginActivity"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="com.example.sdk.LOGIN" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>

我想这样做的原因是我正在开发一个我想在几个项目中使用的 SDK,这是我能弄清楚如何通知作为登录活动的 SDK 的最佳方法,而它是仅在 app 模块中定义。

在我做了这样的声明后,我开始像这样的登录活动(在库和应用程序中):

    Intent intent = new Intent();
    intent.setAction("com.example.sdk.LOGIN");
    context.startActivity(intent);

依赖于同一个 SDK 的两个或多个应用程序可能会同时安装在同一个设备上。如果我理解正确,在这种情况下,在这些应用程序中的每一个中,Activity 启动都会启动一个随机登录活动(应用程序 A 中的调用可能会启动应用程序 B 的登录)。

  1. 我对自定义意图过滤器如何工作的理解是否正确?
  2. 有没有办法告诉应用程序 A 中的调用仅使用应用程序 A 中的意图过滤器声明

也欢迎提出关于重用登录相关逻辑的替代方法的建议,而不依赖于意图过滤器。

4

4 回答 4

2

我想出了一种方法来实现我想要的。

基本上我不会在我的库中对包进行硬编码,而是使用以下方法从库中启动登录活动:

private static final String INTENT_ACTION_PATTERN = "%s.LOGIN";
public void startLoginActivity() {
    Intent intent = new Intent();
    String intentAction = String.format(INTENT_ACTION_PATTERN, mContext.getPackageName());
    intent.setAction(intentAction);
    mContext.startActivity(intent);
}

我将只使用一个约定,我将始终定义自定义意图过滤器以匹配我的应用程序的包:

<activity
    android:name=".view.LoginActivity"
    android:label="@string/app_name">
    <intent-filter>
        <action android:name="com.example.myapp.LOGIN" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
于 2017-11-15T13:25:12.593 回答
1

在这种情况下,在这些应用程序中的每一个中,Activity 启动都会启动一个随机登录活动。

这并不完全正确。来自文档

如果只有一个应用程序可以处理它,则该应用程序会立即打开并给出意图。如果多个活动接受该意图,系统会显示一个对话框,以便用户选择要使用的应用程序。

至于你的第二个问题:

有没有办法告诉应用程序 A 中的调用仅使用应用程序 A 中的意图过滤器声明?

我假设您无法使用显式意图启动活动,因为您无法知道库模块中客户端的活动名称。

没有API 可以为您提供按其intent-filter属性过滤的活动类。PackageManagerAPI 无法提供帮助。这意味着,您无法获取活动的类实例以显式启动活动。这反过来意味着,您的唯一方法是隐式启动活动,如前所述,它将通过对话提示。

于 2017-11-15T08:53:42.833 回答
1

这些是我做的步骤:

  1. 在清单中定义自定义意图过滤器
  2. 在您的活动(您要启动的)内部覆盖onCreateonNewIntent
  3. 通过创建另一个启动自定义意图的应用程序来测试它

清单示例:

<activity
   android:name="com.test.MainActivity">
   <intent-filter>
       <action android:name="test_action_that_should_be_unique"></action>
       <category android:name="android.intent.category.DEFAULT"></category>
   </intent-filter>
</activity>

覆盖活动生命周期:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = getIntent();
        if (intent == null)
            return;
        String action = intent.getAction();
        if (action == null || !action.equals("test_action_that_should_be_unique"))
            return;

        Toast.makeText(this, "onCreate: test_action_that_should_be_unique", Toast.LENGTH_SHORT).show();
    }


 @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        if (intent == null)
            return;
        String action = intent.getAction();
        if (action == null || !action.equals("test_action_that_should_be_unique"))
            return;

        Toast.makeText(this, "onNewIntent: test_action_that_should_be_unique", Toast.LENGTH_SHORT).show();
    }

从其他应用程序测试新的自定义意图:

  Intent intent = new Intent("test_action_that_should_be_unique");
  startActivity(intent);
  • 当然检查上述意图是否为空:

    PackageManager packageManager = getActivity().getPackageManager(); if (intent.resolveActivity(packageManager) != null) { startActivity(intent); }

于 2018-02-12T09:40:02.400 回答
0

我认为更好的解决方案是<meta-data><application>. AndroidManifest您的客户可以在此处指定任何值,然后您可以在库中读取它。因此,您的客户将指定他的类名,LoginActivity您将使用它通过显式 Intent 启动它。

客户端应用程序中的 AndroidManifest

<application ...>
    ...
    <meta-data android:name="com.example.sdk.LOGIN_ACTIVITY" android:value=".view.LoginActivity" />
</application>

在您的库代码中使用

(不要忘记处理特殊情况并添加异常处理)
public void startLoginActivity(Context context) {
    String packageName = context.getPackageName();

    PackageManager pm = context.getPackageManager();
    ApplicationInfo appInfo = pm.getApplicationInfo(packageName, PackgeManager.GET_META_DATA);
    Bundle data = appInfo.metaData;

    String activityName = data.getString("com.example.sdk.LOGIN_ACTIVITY");
    if (activityName == null || activityName.isEmpty()) {
        return;
    }
    ComponentName component = ComponentName.createRelative(packageName, activityName);
    Intent intent = new Intent().setComponent(component);

    context.startActivity(intent);
}
于 2020-12-18T15:33:14.843 回答