Android:设置媒体路由按钮时崩溃

Android: Crash when setting up media route button

我遇到的问题与 几乎相同。 主要区别在于我的项目在调试时执行此操作并在这一行执行

CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), mMediaRouteButton);

我已尝试设置所有变量 public,但这没有任何作用。完整代码为

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button);
    CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), mMediaRouteButton);

    mCastContext = CastContext.getSharedInstance(this);

    mSelector = new MediaRouteSelector.Builder()
            // These are the framework-supported intents
            .addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO)
            .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)
            .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
            .build();
    mMediaRouter = MediaRouter.getInstance(this);
}

我还发现值得一提的是这段代码有效,但我终究无法弄清楚是什么原因导致它停止工作。据我所知,当我在 Android Studio 中使缓存无效时它停止工作。 这是我遇到的错误

java.lang.RuntimeException: Unable to start activity ComponentInfo{mypackage.package/mypackage.package.MainActivity}: java.lang.IllegalStateException: Failed to initialize CastContext.
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
    at android.app.ActivityThread.-wrap12(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6077)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
    Caused by: java.lang.IllegalStateException: Failed to initialize CastContext.
    at com.google.android.gms.cast.framework.CastContext.zzbb(Unknown Source)
    at com.google.android.gms.cast.framework.CastContext.getSharedInstance(Unknown Source)
    at com.google.android.gms.cast.framework.CastButtonFactory.setUpMediaRouteButton(Unknown Source)
    at mypackage.package.MainActivity.onCreate(MainActivity.java:51)
    at android.app.Activity.performCreate(Activity.java:6664)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707) 
    at android.app.ActivityThread.-wrap12(ActivityThread.java) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:6077) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 
    Caused by: java.lang.IllegalAccessException: java.lang.Class<mypackage.package.CastOptionsProvider> is not accessible from java.lang.Class<com.google.android.gms.cast.framework.CastContext>
    at java.lang.Class.newInstance(Native Method)
    at com.google.android.gms.cast.framework.CastContext.zzbb(Unknown Source) 
    at com.google.android.gms.cast.framework.CastContext.getSharedInstance(Unknown Source) 
    at com.google.android.gms.cast.framework.CastButtonFactory.setUpMediaRouteButton(Unknown Source) 
    at mypackage.package.MainActivity.onCreate(MainActivity.java:51) 
    at android.app.Activity.performCreate(Activity.java:6664) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707) 
    at android.app.ActivityThread.-wrap12(ActivityThread.java) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:6077) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 

初始化媒体 CastContext, to properly initialize CastContext, the application must have the implements OptionsProvider 接口的方式可能存在问题:

包 com.example.app;

 public class CastOptionsProvider implements OptionsProvider {
     @Override
     public CastOptions getCastOptions(Context appContext) {
         ...
     }
 }

并在 AndroidManifest.xml 中使用键 OPTIONS_PROVIDER_CLASS_NAME_KEY:

指定其完全限定的 class 名称
  ...
     <meta-data
         android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
         android:value="com.example.app.CastOptionsProvider" />
     ...

注意:所有public方法必须从主线程调用。

我做了一些研究,发现了这张讨论如何初始化 CastContext 的相关 SO 票:How to initialize CastContext outside of onCreate method

这已通过制作 CastOptionsProvider public 得到解决。我不知道为什么一开始会出现这个问题,因为它在 public 之前工作正常,直到它没有。我没有在开始失败的构建中触及 CastOptionsProvider。 我的 CastOptionsProvider 现在看起来像这样

public class CastOptionsProvider implements OptionsProvider {
 @Override
 public CastOptions getCastOptions(Context appContext) {
     CastOptions castOptions = new CastOptions.Builder()
            .setReceiverApplicationId(appContext.getString(R.string.app_id))
            .build();
     return castOptions;
 }
 @Override
 public List<SessionProvider> getAdditionalSessionProviders(Context context) {
    return null;
 }
}

如果这仅发生在发布 buildtype 中,则它与混淆器有关。请将 CastOptionsProvider class 添加到 proguard 文件并重新检查

-keep class abc.xyz.videocast.CastOptionsProvider { *; }

为了更安全,还可以添加这些 classes

-keep class android.support.** { *; }
-keep class com.google.** { *; }