[基本上,我正在将应用程序转换为库模块。问题在于此应用程序具有Chromecast功能,因此清单中具有其自己的CastOptionsProvider
,而打算使用此库的应用程序具有其自己的CastOptionsProvider
,从而导致清单合并失败。
我知道这应该是清单合并的明显问题,但这更多地与应用程序的Chromecast部分有关。一个应用程序能否有2个CastOptionsProvider
投放到2个不同的Receiver Apps中?
TL; DR您可以在库中声明一个OptionsProvider
类,并且如果需要,您的应用程序可以声明自己的OptionsProvider
类以代替使用。 要在应用程序运行时在不同的接收器应用程序之间进行切换,应使用CastContext.setReceiverApplicationId
方法覆盖OptionsProvider
中的设置。
背景
根据Chromecast codelab,CastOptionsProvider
是您自己编写的类。只要实现com.google.android.gms.cast.framework.OptionsProvider
,您就可以实际调用它。这也意味着您可以在同一个应用程序中编写多个CastOptionsProvider
类,只要将它们放在不同的程序包中或给它们指定不同的名称即可。您可以这样声明每个OptionsProvider
:
package your.pkg.goes.here;
import com.google.android.gms.cast.framework.OptionsProvider;
...
public class YourOptionsProvider implements OptionsProvider {
@Override
public CastOptions getCastOptions(Context context) {...}
@Override
public List<SessionProvider> getAdditionalSessionProviders(Context context) {...}
}
到目前为止,很好。由于您可以随意调用OptionsProvider
,因此还需要在清单中声明OPTIONS_PROVIDER_CLASS_NAME
,以便应用程序知道如何获取其强制转换选项。该代码属于您的AndroidManifest.xml
文件,看起来像这样:
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="your.pkg.goes.here.YourOptionsProvider" />
这里是棘手的地方。 meta-data
用于声明键值对,you can't have more than one value for the same key。您可以在代码中浮动多个OptionsProvider
类,这很好,但是强制转换框架一次只能使用其中一个。要更改使用哪一个,您需要编辑清单you can't do while the app is running。您可以做的最接近的事情是使用不同的OptionsProvider
构建不同的应用程序版本。
所以我应该使用哪个OptionProvider?
OptionsProvider
的行为仅由其如何实现功能getCastOptions
和getAdditionalSessionProviders
来定义。从库中找出您需要的行为,然后将该行为编写为可以由您的应用程序扩展的库函数或类。例如:
package your.library;
import com.google.android.gms.cast.framework.CastOptions;
import com.google.android.gms.cast.framework.OptionsProvider;
...
public class LibraryOptionsProvider implements OptionsProvider {
public String YOUR_LIBRARY_APPLICATION_ID = "ASDFASDF";
@Override
public CastOptions getCastOptions(Context context) {
return new CastOptions.Builder()
.setReceiverApplicationId(YOUR_LIBRARY_APPLICATION_ID)
// maybe set some other settings, too
.build();
}
@Override
public List<SessionProvider> getAdditionalSessionProviders(Context context) {...}
}
对于不需要特殊行为的应用程序,您只需将LibraryOptionsProvider
放在应用程序的清单中即可:
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="your.library.LibraryOptionsProvider" />
但是对于需要特殊处理的应用,您可以声明自己的ApplicationOptionsProvider
,并使用LibraryOptionsProvider
进行某些操作。
package your.application;
import your.library.LibraryOptionsProvider;
...
public class ApplicationOptionsProvider extends LibraryOptionsProvider {
@Override
public CastOptions getCastOptions(Context context) {
return new CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.app_id)) // use a different application ID from the one in LibraryOptionsProvider
.build();
}
// inherit getAdditionalSessionProviders from LibraryOptionsProvider, no need to override it unless we want different behavior
}
然后您的清单应指向ApplicationOptionsProvider
而不是LibraryOptionsProvider
:
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="your.application.ApplicationOptionsProvider" />
到目前为止的总结:由应用程序决定是否需要根据其OptionsProvider
的行为。如果不需要特殊行为,则应用程序应使用您在库中声明的OptionsProvider
。当需要自定义行为时(例如,当您需要不同的转换选项或不同的转换应用程序ID时),则应用程序应声明其自己的OptionsProvider
,它可以依赖于库代码而不是重新实现共享行为。
多个应用程序ID
OptionsProvider
用于初始化CastOptions
,这是“包含用于Cast SDK的全局上下文的单例类”(source)。应用启动时,CastContext
在后台初始化,但是您可以随时使用CastContext.setReceiverApplicationId(String applicationId)
更改应用ID。这样,您将忽略在CastOptions
中配置的接收器应用程序ID。 这是在单个版本中可以在多个接收器应用程序之间进行切换的方式。