使用自定义意图操作仅在特定应用程序上下文中启动活动

时间:2017-11-15 08:37:21

标签: android android-intent android-activity intentfilter android-intent-chooser

我需要使用intent filter指定我的登录活动:

    <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 start将启动一个随机登录活动(可能在应用程序A中调用启动应用程序B的登录)。

  1. 我对自定义意图过滤器如何工作的理解是否正确?
  2. 有没有办法告诉应用程序A中的调用只在应用程序A中使用意图过滤器声明
  3. 欢迎重新使用与登录相关的逻辑的替代方法的建议,而不是依赖于意图过滤器。

4 个答案:

答案 0 :(得分: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>

答案 1 :(得分:1)

  

在这些应用程序中的每个应用程序中,Activity start将启动随机登录活动。

这不是真的。来自docs

  

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

至于你的第二个问题:

  

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

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

没有 API,可以为您提供活动类,按其intent-filter属性进行过滤。 PackageManager API无法提供帮助。这意味着,您无法获取活动的类实例以显式启动活动。这反过来意味着,唯一的方法是隐式启动活动,正如已经说过的那样,它将通过对话框进行提示。

答案 2 :(得分:0)

这些是我做的步骤:

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

    清单示例:

    <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);
    
    • 当然请检查上述null意图:

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

答案 3 :(得分: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);
}