Skip to content

Commit 9bb0c8b

Browse files
derekrossclaude
andcommitted
fix: chromecast casting and local playback issues
- Add ProGuard rules to preserve Google Cast SDK classes - Fix Capacitor plugin dist files to properly register native plugin - Improve Cast initialization with retry logic in initialize() - Prevent local audio playback when casting (check isCasting in canplay handler) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3fc2b6d commit 9bb0c8b

File tree

6 files changed

+74
-47
lines changed

6 files changed

+74
-47
lines changed

android/app/proguard-rules.pro

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,15 @@
1919
# If you keep the line number information, uncomment this to
2020
# hide the original source file name.
2121
#-renamesourcefileattribute SourceFile
22+
23+
# Google Cast SDK - preserve all Cast framework classes
24+
-keep class com.google.android.gms.cast.** { *; }
25+
-keep class com.google.android.gms.cast.framework.** { *; }
26+
-keep class com.google.android.gms.common.** { *; }
27+
28+
# Keep CastOptionsProvider
29+
-keep class com.gameleap.plugins.chromecast.lib.CastOptionsProvider { *; }
30+
-keep class * extends com.google.android.gms.cast.framework.OptionsProvider { *; }
31+
32+
# Keep MediaRouter classes
33+
-keep class androidx.mediarouter.** { *; }

plugins/capacitor-chromecast/android/src/main/java/com/gameleap/plugins/chromecast/ChromecastConnection.java

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,38 @@ ChromecastSession getChromecastSession() {
132132
public void initialize(final String applicationId, final PluginCall pluginCall) {
133133
activity.runOnUiThread(new Runnable() {
134134
public void run() {
135-
// Check if Cast is available (GMS must be present)
136-
if (!castAvailable) {
137-
android.util.Log.i("ChromecastConnection", "Cast not available during initialize - GMS may be missing");
138-
pluginCall.reject("Google Play Services not available - Cast disabled");
139-
return;
135+
// Try to initialize Cast if not already done
136+
if (!castAvailable && cachedCastContext == null) {
137+
// Check if Google Play Services is available
138+
if (!isGooglePlayServicesAvailable()) {
139+
android.util.Log.i("ChromecastConnection", "Google Play Services not available - Cast disabled");
140+
pluginCall.reject("Google Play Services not available - Cast disabled");
141+
return;
142+
}
143+
144+
// Try to get CastContext
145+
try {
146+
CastContext ctx = getContext();
147+
if (ctx != null) {
148+
if (listener != null) {
149+
ctx.addCastStateListener(listener);
150+
}
151+
castAvailable = true;
152+
android.util.Log.i("ChromecastConnection", "Cast initialized successfully in initialize()");
153+
} else {
154+
android.util.Log.w("ChromecastConnection", "CastContext is null");
155+
pluginCall.reject("Cast framework not available");
156+
return;
157+
}
158+
} catch (Exception e) {
159+
android.util.Log.e("ChromecastConnection", "Failed to initialize Cast in initialize(): " + e.getMessage());
160+
pluginCall.reject("Cast framework error: " + e.getMessage());
161+
return;
162+
} catch (Throwable t) {
163+
android.util.Log.e("ChromecastConnection", "Cast framework error in initialize(): " + t.getMessage());
164+
pluginCall.reject("Cast framework error: " + t.getMessage());
165+
return;
166+
}
140167
}
141168

142169
// If the app Id changed
Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
// Web stub for Chromecast plugin - native only
2-
export const Chromecast = {
3-
initialize: () => Promise.reject('Chromecast is only available on native platforms'),
4-
requestSession: () => Promise.reject('Chromecast is only available on native platforms'),
5-
launchMedia: () => Promise.reject('Chromecast is only available on native platforms'),
6-
castPlay: () => Promise.reject('Chromecast is only available on native platforms'),
7-
castPause: () => Promise.reject('Chromecast is only available on native platforms'),
8-
castStop: () => Promise.reject('Chromecast is only available on native platforms'),
9-
endSession: () => Promise.reject('Chromecast is only available on native platforms'),
10-
addListener: () => Promise.resolve({ remove: () => {} }),
11-
};
1+
import { registerPlugin } from '@capacitor/core';
2+
const Chromecast = registerPlugin('Chromecast', {
3+
web: () => import('./web').then(m => new m.ChromecastWeb()),
4+
});
5+
export { Chromecast };
Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
// Web stub for Chromecast plugin - native only
2-
const Chromecast = {
3-
initialize: () => Promise.reject('Chromecast is only available on native platforms'),
4-
requestSession: () => Promise.reject('Chromecast is only available on native platforms'),
5-
launchMedia: () => Promise.reject('Chromecast is only available on native platforms'),
6-
castPlay: () => Promise.reject('Chromecast is only available on native platforms'),
7-
castPause: () => Promise.reject('Chromecast is only available on native platforms'),
8-
castStop: () => Promise.reject('Chromecast is only available on native platforms'),
9-
endSession: () => Promise.reject('Chromecast is only available on native platforms'),
10-
addListener: () => Promise.resolve({ remove: () => {} }),
11-
};
12-
13-
module.exports = { Chromecast };
1+
'use strict';
2+
3+
Object.defineProperty(exports, '__esModule', { value: true });
4+
5+
var core = require('@capacitor/core');
6+
7+
const Chromecast = core.registerPlugin('Chromecast', {
8+
web: () => Promise.resolve().then(function () { return require('./web'); }).then(m => new m.ChromecastWeb()),
9+
});
10+
11+
exports.Chromecast = Chromecast;
Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
1-
// Web stub for Chromecast plugin - native only
2-
var capacitorChromecast = (function (exports) {
3-
'use strict';
1+
var capacitorChromecast = (function (exports, core) {
2+
'use strict';
43

5-
const Chromecast = {
6-
initialize: () => Promise.reject('Chromecast is only available on native platforms'),
7-
requestSession: () => Promise.reject('Chromecast is only available on native platforms'),
8-
launchMedia: () => Promise.reject('Chromecast is only available on native platforms'),
9-
castPlay: () => Promise.reject('Chromecast is only available on native platforms'),
10-
castPause: () => Promise.reject('Chromecast is only available on native platforms'),
11-
castStop: () => Promise.reject('Chromecast is only available on native platforms'),
12-
endSession: () => Promise.reject('Chromecast is only available on native platforms'),
13-
addListener: () => Promise.resolve({ remove: () => {} }),
14-
};
4+
const Chromecast = core.registerPlugin('Chromecast', {
5+
web: () => Promise.resolve().then(function () { return require('./web'); }).then(m => new m.ChromecastWeb()),
6+
});
157

16-
exports.Chromecast = Chromecast;
8+
exports.Chromecast = Chromecast;
179

18-
return exports;
19-
})({});
10+
Object.defineProperty(exports, '__esModule', { value: true });
11+
12+
return exports;
13+
14+
})({}, capacitorExports);

src/contexts/MusicPlayerContext.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ export function MusicPlayerProvider({ children }: { children: React.ReactNode })
221221
const handleCanPlay = () => {
222222
console.log('Audio can play');
223223
dispatch({ type: 'SET_LOADING', payload: false });
224-
if (state.isPlaying) {
224+
// Don't auto-play locally when casting
225+
if (state.isPlaying && !state.isCasting) {
225226
audio.play().catch((error) => {
226227
console.error('Audio play failed on canplay:', error);
227228
if (error.name === 'NotAllowedError') {
@@ -263,7 +264,7 @@ export function MusicPlayerProvider({ children }: { children: React.ReactNode })
263264
audio.removeEventListener('ended', handleEnded);
264265
audio.removeEventListener('error', handleError);
265266
};
266-
}, [state.isPlaying]);
267+
}, [state.isPlaying, state.isCasting]);
267268

268269
// Update audio source when track changes
269270
useEffect(() => {

0 commit comments

Comments
 (0)