1.6.1
This commit is contained in:
parent
8ac9590a8f
commit
142dcebaae
@ -524,7 +524,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 100;
|
||||
CURRENT_PROJECT_VERSION = 161;
|
||||
DEVELOPMENT_TEAM = S9YG87C297;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@ -533,7 +533,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
MARKETING_VERSION = 1.6.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -715,7 +715,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 100;
|
||||
CURRENT_PROJECT_VERSION = 161;
|
||||
DEVELOPMENT_TEAM = S9YG87C297;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@ -724,7 +724,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
MARKETING_VERSION = 1.6.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -744,7 +744,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 100;
|
||||
CURRENT_PROJECT_VERSION = 161;
|
||||
DEVELOPMENT_TEAM = S9YG87C297;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@ -753,7 +753,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
MARKETING_VERSION = 1.6.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
||||
@ -7,7 +7,6 @@ class BaishunBridgeActions {
|
||||
static const String gameLoaded = 'gameLoaded';
|
||||
static const String gameRecharge = 'gameRecharge';
|
||||
static const String destroy = 'destroy';
|
||||
static const String debugLog = 'debugLog';
|
||||
}
|
||||
|
||||
class BaishunBridgeMessage {
|
||||
@ -104,45 +103,6 @@ class BaishunJsBridge {
|
||||
$channelName.postMessage(JSON.stringify({ action: action, payload: payload }));
|
||||
return payload;
|
||||
}
|
||||
function clipText(value, limit) {
|
||||
const text = (value == null ? '' : String(value)).trim();
|
||||
if (!text) {
|
||||
return '';
|
||||
}
|
||||
return text.length > limit ? text.slice(0, limit) + '...' : text;
|
||||
}
|
||||
function stringifyForLog(value) {
|
||||
if (value == null) {
|
||||
return '';
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
return clipText(value, 320);
|
||||
}
|
||||
try {
|
||||
return clipText(JSON.stringify(value), 320);
|
||||
} catch (_) {
|
||||
return clipText(String(value), 320);
|
||||
}
|
||||
}
|
||||
function postDebug(tag, payload) {
|
||||
$channelName.postMessage(JSON.stringify({
|
||||
action: '${BaishunBridgeActions.debugLog}',
|
||||
payload: {
|
||||
tag: tag,
|
||||
message: stringifyForLog(payload)
|
||||
}
|
||||
}));
|
||||
}
|
||||
function maskText(value) {
|
||||
const text = (value == null ? '' : String(value)).trim();
|
||||
if (!text) {
|
||||
return '';
|
||||
}
|
||||
if (text.length <= 10) {
|
||||
return text;
|
||||
}
|
||||
return text.slice(0, 6) + '***' + text.slice(-4);
|
||||
}
|
||||
function ensureChannelAlias(name, handler) {
|
||||
if (!window[name] || typeof window[name].postMessage !== 'function') {
|
||||
window[name] = { postMessage: handler };
|
||||
@ -156,30 +116,21 @@ class BaishunJsBridge {
|
||||
}
|
||||
}
|
||||
window.NativeBridge.getConfigSync = function() {
|
||||
postDebug('bridge.getConfigSync', {
|
||||
hasConfig: !!window.__baishunLastConfig,
|
||||
hasNativeBridgeConfig: !!(window.NativeBridge && window.NativeBridge.config)
|
||||
});
|
||||
return window.__baishunLastConfig || null;
|
||||
};
|
||||
window.NativeBridge.getConfig = function(params) {
|
||||
postDebug('bridge.getConfig.call', toPayload(params));
|
||||
postAction('${BaishunBridgeActions.getConfig}', params);
|
||||
return window.__baishunLastConfig || null;
|
||||
};
|
||||
window.NativeBridge.destroy = function(payload) {
|
||||
postDebug('bridge.destroy.call', toPayload(payload));
|
||||
postAction('${BaishunBridgeActions.destroy}', payload);
|
||||
};
|
||||
window.NativeBridge.gameRecharge = function(payload) {
|
||||
postDebug('bridge.gameRecharge.call', toPayload(payload));
|
||||
postAction('${BaishunBridgeActions.gameRecharge}', payload);
|
||||
};
|
||||
window.NativeBridge.gameLoaded = function(payload) {
|
||||
postDebug('bridge.gameLoaded.call', toPayload(payload));
|
||||
postAction('${BaishunBridgeActions.gameLoaded}', payload);
|
||||
};
|
||||
window.__baishunDebugLog = postDebug;
|
||||
ensureChannelAlias('getConfig', function(message) {
|
||||
window.NativeBridge.getConfig(message);
|
||||
});
|
||||
@ -204,163 +155,6 @@ class BaishunJsBridge {
|
||||
ensureWebkitHandler('gameLoaded', function(message) {
|
||||
window.NativeBridge.gameLoaded(message);
|
||||
});
|
||||
if (!window.__baishunNetworkDebugReady) {
|
||||
window.__baishunNetworkDebugReady = true;
|
||||
if (typeof document !== 'undefined' && typeof document.addEventListener === 'function' && !window.__baishunInputDebugReady) {
|
||||
window.__baishunInputDebugReady = true;
|
||||
window.__baishunInputDebugCount = 0;
|
||||
['pointerdown', 'touchstart', 'mousedown', 'click'].forEach(function(eventName) {
|
||||
document.addEventListener(eventName, function(event) {
|
||||
if ((window.__baishunInputDebugCount || 0) >= 24) {
|
||||
return;
|
||||
}
|
||||
window.__baishunInputDebugCount = (window.__baishunInputDebugCount || 0) + 1;
|
||||
const target = event && event.target;
|
||||
const touch = event && event.touches && event.touches.length ? event.touches[0] : null;
|
||||
postDebug('input.' + eventName, {
|
||||
x: touch ? touch.clientX : (event && event.clientX),
|
||||
y: touch ? touch.clientY : (event && event.clientY),
|
||||
pointerType: event && event.pointerType,
|
||||
targetTag: target && target.tagName,
|
||||
targetId: target && target.id,
|
||||
targetClass: target && target.className
|
||||
});
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
if (typeof window.addEventListener === 'function') {
|
||||
window.addEventListener('error', function(event) {
|
||||
const target = event && event.target;
|
||||
if (target && target !== window) {
|
||||
postDebug('resource.error', {
|
||||
tag: target.tagName || '',
|
||||
source: target.currentSrc || target.src || target.href || '',
|
||||
outerHTML: target.outerHTML || ''
|
||||
});
|
||||
return;
|
||||
}
|
||||
postDebug('window.error', {
|
||||
message: event && event.message,
|
||||
source: event && event.filename,
|
||||
line: event && event.lineno,
|
||||
column: event && event.colno,
|
||||
stack: event && event.error && event.error.stack
|
||||
});
|
||||
}, true);
|
||||
window.addEventListener('unhandledrejection', function(event) {
|
||||
postDebug('promise.reject', {
|
||||
reason: event && event.reason
|
||||
});
|
||||
});
|
||||
}
|
||||
if (window.console && !window.__baishunConsoleDebugReady) {
|
||||
window.__baishunConsoleDebugReady = true;
|
||||
['log', 'info', 'warn', 'error'].forEach(function(level) {
|
||||
const original = typeof window.console[level] === 'function'
|
||||
? window.console[level].bind(window.console)
|
||||
: null;
|
||||
window.console[level] = function() {
|
||||
try {
|
||||
postDebug('console.' + level, Array.prototype.slice.call(arguments));
|
||||
} catch (_) {}
|
||||
if (original) {
|
||||
return original.apply(window.console, arguments);
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
});
|
||||
}
|
||||
if (typeof window.fetch === 'function') {
|
||||
const originalFetch = window.fetch.bind(window);
|
||||
window.fetch = function(input, init) {
|
||||
const url = typeof input === 'string' ? input : (input && input.url) || '';
|
||||
const method = (init && init.method) || 'GET';
|
||||
postDebug('fetch.start', { method: method, url: url });
|
||||
return originalFetch(input, init)
|
||||
.then(function(response) {
|
||||
const cloned = response && typeof response.clone === 'function' ? response.clone() : null;
|
||||
if (cloned && typeof cloned.text === 'function') {
|
||||
cloned.text().then(function(text) {
|
||||
if (!response.ok || /failed|error|exception|get user info/i.test(text)) {
|
||||
postDebug('fetch.end', {
|
||||
method: method,
|
||||
url: url,
|
||||
status: response.status,
|
||||
body: text
|
||||
});
|
||||
} else {
|
||||
postDebug('fetch.end', {
|
||||
method: method,
|
||||
url: url,
|
||||
status: response.status
|
||||
});
|
||||
}
|
||||
}).catch(function(error) {
|
||||
postDebug('fetch.readError', {
|
||||
method: method,
|
||||
url: url,
|
||||
error: error && error.message ? error.message : String(error)
|
||||
});
|
||||
});
|
||||
} else {
|
||||
postDebug('fetch.end', {
|
||||
method: method,
|
||||
url: url,
|
||||
status: response && response.status
|
||||
});
|
||||
}
|
||||
return response;
|
||||
})
|
||||
.catch(function(error) {
|
||||
postDebug('fetch.error', {
|
||||
method: method,
|
||||
url: url,
|
||||
error: error && error.message ? error.message : String(error)
|
||||
});
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
}
|
||||
if (window.XMLHttpRequest && window.XMLHttpRequest.prototype) {
|
||||
const xhrOpen = window.XMLHttpRequest.prototype.open;
|
||||
const xhrSend = window.XMLHttpRequest.prototype.send;
|
||||
window.XMLHttpRequest.prototype.open = function(method, url) {
|
||||
this.__baishunMethod = method || 'GET';
|
||||
this.__baishunUrl = url || '';
|
||||
return xhrOpen.apply(this, arguments);
|
||||
};
|
||||
window.XMLHttpRequest.prototype.send = function(body) {
|
||||
const method = this.__baishunMethod || 'GET';
|
||||
const url = this.__baishunUrl || '';
|
||||
postDebug('xhr.start', { method: method, url: url });
|
||||
this.addEventListener('loadend', function() {
|
||||
const responseText = typeof this.responseText === 'string' ? this.responseText : '';
|
||||
if (this.status >= 400 || /failed|error|exception|get user info/i.test(responseText)) {
|
||||
postDebug('xhr.end', {
|
||||
method: method,
|
||||
url: url,
|
||||
status: this.status,
|
||||
body: responseText
|
||||
});
|
||||
} else {
|
||||
postDebug('xhr.end', {
|
||||
method: method,
|
||||
url: url,
|
||||
status: this.status
|
||||
});
|
||||
}
|
||||
});
|
||||
this.addEventListener('error', function() {
|
||||
postDebug('xhr.error', {
|
||||
method: method,
|
||||
url: url,
|
||||
status: this.status
|
||||
});
|
||||
});
|
||||
return xhrSend.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
}
|
||||
window.baishunChannel = window.baishunChannel || {};
|
||||
window.baishunChannel.walletUpdate = function(payload) {
|
||||
window.__baishunLastWalletPayload = payload || {};
|
||||
@ -377,10 +171,6 @@ class BaishunJsBridge {
|
||||
if (typeof window.dispatchEvent === 'function' && typeof CustomEvent === 'function') {
|
||||
window.dispatchEvent(new CustomEvent('baishunBridgeReady'));
|
||||
}
|
||||
postDebug('bridge.ready', {
|
||||
href: window.location && window.location.href,
|
||||
ua: navigator && navigator.userAgent
|
||||
});
|
||||
})();
|
||||
''';
|
||||
}
|
||||
@ -395,16 +185,6 @@ class BaishunJsBridge {
|
||||
(function() {
|
||||
const config = $payload;
|
||||
const explicitCallbackPath = $encodedCallbackPath;
|
||||
function maskText(value) {
|
||||
const text = (value == null ? '' : String(value)).trim();
|
||||
if (!text) {
|
||||
return '';
|
||||
}
|
||||
if (text.length <= 10) {
|
||||
return text;
|
||||
}
|
||||
return text.slice(0, 6) + '***' + text.slice(-4);
|
||||
}
|
||||
function resolvePath(path) {
|
||||
if (!path || typeof path !== 'string') {
|
||||
return null;
|
||||
@ -444,20 +224,6 @@ class BaishunJsBridge {
|
||||
if (explicitCallbackPath) {
|
||||
window.__baishunLastJsCallback = explicitCallbackPath;
|
||||
}
|
||||
if (typeof window.__baishunDebugLog === 'function') {
|
||||
window.__baishunDebugLog('config.deliver', {
|
||||
appId: config.appId,
|
||||
appChannel: config.appChannel,
|
||||
userId: config.userId,
|
||||
roomId: config.roomId,
|
||||
gameMode: config.gameMode,
|
||||
language: config.language,
|
||||
gsp: config.gsp,
|
||||
code: maskText(config.code),
|
||||
codeLength: config.code ? String(config.code).length : 0,
|
||||
callbackPath: callbackPath
|
||||
});
|
||||
}
|
||||
if (typeof window.__baishunGetConfigCallback === 'function') {
|
||||
window.__baishunGetConfigCallback(config);
|
||||
window.__baishunGetConfigCallback = null;
|
||||
@ -465,14 +231,6 @@ class BaishunJsBridge {
|
||||
if (window.__baishunLastJsCallback) {
|
||||
callbackInvoked = invokeCallbackPath(window.__baishunLastJsCallback) || callbackInvoked;
|
||||
}
|
||||
if (typeof window.__baishunDebugLog === 'function') {
|
||||
window.__baishunDebugLog('config.callback', {
|
||||
callbackPath: callbackPath,
|
||||
callbackInvoked: callbackInvoked,
|
||||
hasLegacyCallback: typeof window.__baishunGetConfigCallback === 'function',
|
||||
hasOnBaishunConfig: typeof window.onBaishunConfig === 'function'
|
||||
});
|
||||
}
|
||||
if (typeof window.onBaishunConfig === 'function') {
|
||||
window.onBaishunConfig(config);
|
||||
}
|
||||
@ -494,9 +252,6 @@ class BaishunJsBridge {
|
||||
return '''
|
||||
(function() {
|
||||
const payload = $safePayload;
|
||||
if (typeof window.__baishunDebugLog === 'function') {
|
||||
window.__baishunDebugLog('wallet.update', payload);
|
||||
}
|
||||
if (window.baishunChannel && typeof window.baishunChannel.walletUpdate === 'function') {
|
||||
window.baishunChannel.walletUpdate(payload);
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ class LeaderBridgeActions {
|
||||
static const String pay = 'pay';
|
||||
static const String closeGame = 'closeGame';
|
||||
static const String loadComplete = 'loadComplete';
|
||||
static const String debugLog = 'debugLog';
|
||||
}
|
||||
|
||||
class LeaderBridgeMessage {
|
||||
@ -88,21 +87,6 @@ class LeaderJsBridge {
|
||||
return {};
|
||||
}
|
||||
|
||||
function stringifyForLog(value) {
|
||||
if (value == null) {
|
||||
return '';
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
return value.length > 320 ? value.slice(0, 320) + '...' : value;
|
||||
}
|
||||
try {
|
||||
const text = JSON.stringify(value);
|
||||
return text.length > 320 ? text.slice(0, 320) + '...' : text;
|
||||
} catch (_) {
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
function postMessage(action, input) {
|
||||
const payload = toPayload(input);
|
||||
$channelName.postMessage(JSON.stringify({
|
||||
@ -112,13 +96,6 @@ class LeaderJsBridge {
|
||||
return payload;
|
||||
}
|
||||
|
||||
function postDebug(tag, payload) {
|
||||
postMessage('${LeaderBridgeActions.debugLog}', {
|
||||
tag: tag,
|
||||
message: stringifyForLog(payload)
|
||||
});
|
||||
}
|
||||
|
||||
function invokeCallback(callback, payload) {
|
||||
if (typeof callback === 'function') {
|
||||
callback(payload);
|
||||
@ -199,16 +176,6 @@ class LeaderJsBridge {
|
||||
};
|
||||
if (payloadChanged) {
|
||||
dispatchConfigReady(normalizedPayload);
|
||||
postDebug('config.ready', {
|
||||
provider: normalizedPayload.provider || '',
|
||||
gameId: normalizedPayload.gameId || '',
|
||||
roomId: launchConfig.roomId || '',
|
||||
code: launchConfig.code
|
||||
? String(launchConfig.code).slice(0, 6) + '***'
|
||||
: '',
|
||||
codeLength: launchConfig.code ? String(launchConfig.code).length : 0,
|
||||
entryUrl: entry.entryUrl || ''
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,12 +201,6 @@ class LeaderJsBridge {
|
||||
window.NativeBridge.pay = pay;
|
||||
window.NativeBridge.closeGame = closeGame;
|
||||
window.NativeBridge.loadComplete = loadComplete;
|
||||
|
||||
window.__leaderBridgeDebug = postDebug;
|
||||
postDebug('bridge.ready', {
|
||||
href: window.location && window.location.href,
|
||||
hasUpdateCoin: typeof window.updateCoin === 'function'
|
||||
});
|
||||
}
|
||||
|
||||
applyLaunchPayload(launchPayload);
|
||||
@ -262,13 +223,6 @@ class LeaderJsBridge {
|
||||
window.onUpdateCoin();
|
||||
return;
|
||||
}
|
||||
$channelName.postMessage(JSON.stringify({
|
||||
action: '${LeaderBridgeActions.debugLog}',
|
||||
payload: {
|
||||
tag: 'game.updateCoin.missing',
|
||||
message: 'No updateCoin handler found on game page.'
|
||||
}
|
||||
}));
|
||||
})();
|
||||
''';
|
||||
}
|
||||
|
||||
@ -299,12 +299,6 @@ class _BaishunGamePageState extends State<BaishunGamePage> {
|
||||
Future<void> _dispatchBridgeMessage(
|
||||
BaishunBridgeMessage bridgeMessage,
|
||||
) async {
|
||||
if (bridgeMessage.action == BaishunBridgeActions.debugLog) {
|
||||
final tag = bridgeMessage.payload['tag']?.toString().trim();
|
||||
final message = bridgeMessage.payload['message']?.toString() ?? '';
|
||||
_log('h5_debug tag=${tag ?? 'unknown'} message=${_clip(message, 800)}');
|
||||
return;
|
||||
}
|
||||
final callbackPath = _extractCallbackPath(bridgeMessage.payload);
|
||||
_log(
|
||||
'bridge_action action=${bridgeMessage.action} '
|
||||
|
||||
@ -245,13 +245,6 @@ class _LeaderGamePageState extends State<LeaderGamePage> {
|
||||
}
|
||||
|
||||
Future<void> _dispatchBridgeMessage(LeaderBridgeMessage bridgeMessage) async {
|
||||
if (bridgeMessage.action == LeaderBridgeActions.debugLog) {
|
||||
final tag = bridgeMessage.payload['tag']?.toString().trim();
|
||||
final message = bridgeMessage.payload['message']?.toString() ?? '';
|
||||
_log('h5_debug tag=${tag ?? 'unknown'} message=${_clip(message, 800)}');
|
||||
return;
|
||||
}
|
||||
|
||||
_didReceiveBridgeMessage = true;
|
||||
_stopBridgeBootstrap(reason: 'bridge_message_${bridgeMessage.action}');
|
||||
_log(
|
||||
|
||||
@ -568,6 +568,7 @@ class _GiftWallSvgaEffectOverlayState extends State<_GiftWallSvgaEffectOverlay>
|
||||
late final SVGAAnimationController _controller;
|
||||
bool _loaded = false;
|
||||
bool _finished = false;
|
||||
String? _retainedResource;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -586,7 +587,10 @@ class _GiftWallSvgaEffectOverlayState extends State<_GiftWallSvgaEffectOverlay>
|
||||
Future<void> _loadAndPlay() async {
|
||||
try {
|
||||
final movieEntity = await _loadMovieEntity(widget.sourceUrl);
|
||||
if (!mounted || _finished) return;
|
||||
if (!mounted || _finished) {
|
||||
_releaseRetainedResource();
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_loaded = true;
|
||||
_controller.videoItem = movieEntity;
|
||||
@ -600,9 +604,12 @@ class _GiftWallSvgaEffectOverlayState extends State<_GiftWallSvgaEffectOverlay>
|
||||
}
|
||||
|
||||
Future<MovieEntity> _loadMovieEntity(String sourceUrl) async {
|
||||
final cache = SCGiftVapSvgaManager().videoItemCache;
|
||||
final cached = cache[sourceUrl];
|
||||
if (cached != null) return cached;
|
||||
final manager = SCGiftVapSvgaManager();
|
||||
final cached = manager.getCachedSvgaEntity(sourceUrl, retain: true);
|
||||
if (cached != null) {
|
||||
_replaceRetainedResource(sourceUrl);
|
||||
return cached;
|
||||
}
|
||||
|
||||
final pathType = SCPathUtils.getPathType(sourceUrl);
|
||||
late final MovieEntity movieEntity;
|
||||
@ -617,10 +624,35 @@ class _GiftWallSvgaEffectOverlayState extends State<_GiftWallSvgaEffectOverlay>
|
||||
throw Exception("Unsupported SVGA source: $sourceUrl");
|
||||
}
|
||||
movieEntity.autorelease = false;
|
||||
cache[sourceUrl] = movieEntity;
|
||||
if (!mounted || _finished) {
|
||||
movieEntity.dispose();
|
||||
return movieEntity;
|
||||
}
|
||||
manager.cacheSvgaEntity(sourceUrl, movieEntity, retain: true);
|
||||
_replaceRetainedResource(sourceUrl);
|
||||
return movieEntity;
|
||||
}
|
||||
|
||||
void _replaceRetainedResource(String resource) {
|
||||
final previous = _retainedResource;
|
||||
if (previous == resource) {
|
||||
return;
|
||||
}
|
||||
if (previous != null) {
|
||||
SCGiftVapSvgaManager().releaseCachedSvgaEntity(previous);
|
||||
}
|
||||
_retainedResource = resource;
|
||||
}
|
||||
|
||||
void _releaseRetainedResource() {
|
||||
final resource = _retainedResource;
|
||||
if (resource == null) {
|
||||
return;
|
||||
}
|
||||
_retainedResource = null;
|
||||
SCGiftVapSvgaManager().releaseCachedSvgaEntity(resource);
|
||||
}
|
||||
|
||||
void _finish() {
|
||||
if (_finished) return;
|
||||
_finished = true;
|
||||
@ -629,6 +661,7 @@ class _GiftWallSvgaEffectOverlayState extends State<_GiftWallSvgaEffectOverlay>
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_releaseRetainedResource();
|
||||
_controller.removeStatusListener(_handleStatusChanged);
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
|
||||
@ -91,11 +91,13 @@
|
||||
// if (_isDisposed) return;
|
||||
// if (SCPathUtils.getFileExtension(task.path).toLowerCase() == ".svga") {
|
||||
// MovieEntity entity;
|
||||
// if (SCGiftVapSvgaManager().videoItemCache.containsKey(task.path)) {
|
||||
// entity = SCGiftVapSvgaManager().videoItemCache[task.path]!;
|
||||
// final manager = SCGiftVapSvgaManager();
|
||||
// final cached = manager.getCachedSvgaEntity(task.path);
|
||||
// if (cached != null) {
|
||||
// entity = cached;
|
||||
// } else {
|
||||
// entity = await SVGAParser.shared.decodeFromAssets(task.path);
|
||||
// SCGiftVapSvgaManager().videoItemCache[task.path] = entity;
|
||||
// manager.cacheSvgaEntity(task.path, entity);
|
||||
// }
|
||||
// _roomGiftsvgaController?.videoItem = entity;
|
||||
// _roomGiftsvgaController?.reset();
|
||||
@ -116,14 +118,16 @@
|
||||
// if (_isDisposed) return;
|
||||
// if (SCPathUtils.getFileExtension(task.path).toLowerCase() == ".svga") {
|
||||
// MovieEntity? entity;
|
||||
// if (SCGiftVapSvgaManager().videoItemCache.containsKey(task.path)) {
|
||||
// entity = SCGiftVapSvgaManager().videoItemCache[task.path]!;
|
||||
// final manager = SCGiftVapSvgaManager();
|
||||
// final cached = manager.getCachedSvgaEntity(task.path);
|
||||
// if (cached != null) {
|
||||
// entity = cached;
|
||||
// entity.autorelease = false;
|
||||
// } else {
|
||||
// try {
|
||||
// entity = await SVGAParser.shared.decodeFromURL(task.path);
|
||||
// entity.autorelease = false;
|
||||
// SCGiftVapSvgaManager().videoItemCache[task.path] = entity;
|
||||
// manager.cacheSvgaEntity(task.path, entity);
|
||||
// } catch (e) {
|
||||
// _isPlaying = false;
|
||||
// }
|
||||
|
||||
@ -26,12 +26,13 @@ class SCGiftVapSvgaManager {
|
||||
static const int _maxConsecutiveEntryTasksBeforeGift = 2;
|
||||
static const Duration _taskWatchdogTimeout = Duration(seconds: 20);
|
||||
static const Duration _entryTaskTtl = Duration(seconds: 6);
|
||||
Map<String, MovieEntity> videoItemCache = {};
|
||||
final Map<String, MovieEntity> _videoItemCache = {};
|
||||
static SCGiftVapSvgaManager? _inst;
|
||||
static const int _maxPreloadConcurrency = 1;
|
||||
static const int _maxPreloadQueueLength = 12;
|
||||
static const int _maxSvgaCacheEntries = 8;
|
||||
static const int _maxPlayablePathCacheEntries = 24;
|
||||
final Map<String, int> _svgaRetainCounts = {};
|
||||
|
||||
SCGiftVapSvgaManager._internal();
|
||||
|
||||
@ -144,7 +145,7 @@ class SCGiftVapSvgaManager {
|
||||
|
||||
bool _isPreloadedOrLoading(String path) {
|
||||
if (_needsSvgaController(path)) {
|
||||
return videoItemCache.containsKey(path) ||
|
||||
return _videoItemCache.containsKey(path) ||
|
||||
_svgaLoadTasks.containsKey(path);
|
||||
}
|
||||
final pathType = SCPathUtils.getPathType(path);
|
||||
@ -302,20 +303,80 @@ class SCGiftVapSvgaManager {
|
||||
}
|
||||
}
|
||||
|
||||
MovieEntity? getCachedSvgaEntity(String path, {bool retain = false}) {
|
||||
final normalizedPath = path.trim();
|
||||
if (normalizedPath.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final entity = _touchCachedSvgaEntity(normalizedPath);
|
||||
if (entity != null && retain) {
|
||||
_retainCachedSvgaEntity(normalizedPath);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
void cacheSvgaEntity(String path, MovieEntity entity, {bool retain = false}) {
|
||||
final normalizedPath = path.trim();
|
||||
if (normalizedPath.isEmpty) {
|
||||
_disposeSvgaEntityIfUnused(entity);
|
||||
return;
|
||||
}
|
||||
_cacheSvgaEntity(normalizedPath, entity);
|
||||
if (retain) {
|
||||
_retainCachedSvgaEntity(normalizedPath);
|
||||
}
|
||||
}
|
||||
|
||||
MovieEntity? removeCachedSvgaEntity(String path, {bool dispose = false}) {
|
||||
final normalizedPath = path.trim();
|
||||
if (normalizedPath.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final entity = _videoItemCache.remove(normalizedPath);
|
||||
if (dispose &&
|
||||
entity != null &&
|
||||
!_isCachedSvgaEntityInUse(normalizedPath, entity)) {
|
||||
_disposeSvgaEntityIfUnused(entity);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
void releaseCachedSvgaEntity(String path) {
|
||||
final normalizedPath = path.trim();
|
||||
if (normalizedPath.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final count = _svgaRetainCounts[normalizedPath] ?? 0;
|
||||
if (count <= 1) {
|
||||
_svgaRetainCounts.remove(normalizedPath);
|
||||
_trimSvgaCache();
|
||||
return;
|
||||
}
|
||||
_svgaRetainCounts[normalizedPath] = count - 1;
|
||||
}
|
||||
|
||||
int get cachedSvgaEntityCount => _videoItemCache.length;
|
||||
|
||||
void _retainCachedSvgaEntity(String path) {
|
||||
_svgaRetainCounts[path] = (_svgaRetainCounts[path] ?? 0) + 1;
|
||||
}
|
||||
|
||||
MovieEntity? _touchCachedSvgaEntity(String path) {
|
||||
final cached = videoItemCache.remove(path);
|
||||
final cached = _videoItemCache.remove(path);
|
||||
if (cached != null) {
|
||||
videoItemCache[path] = cached;
|
||||
_videoItemCache[path] = cached;
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
|
||||
void _cacheSvgaEntity(String path, MovieEntity entity) {
|
||||
final previous = videoItemCache.remove(path);
|
||||
if (previous != null && !identical(previous, entity)) {
|
||||
final previous = _videoItemCache.remove(path);
|
||||
if (previous != null &&
|
||||
!identical(previous, entity) &&
|
||||
!_isCachedSvgaEntityInUse(path, previous)) {
|
||||
_disposeSvgaEntityIfUnused(previous);
|
||||
}
|
||||
videoItemCache[path] = entity;
|
||||
_videoItemCache[path] = entity;
|
||||
_trimSvgaCache();
|
||||
}
|
||||
|
||||
@ -334,17 +395,19 @@ class SCGiftVapSvgaManager {
|
||||
}
|
||||
|
||||
void _trimSvgaCache() {
|
||||
while (videoItemCache.length > _maxSvgaCacheEntries) {
|
||||
final removableEntry = videoItemCache.entries.firstWhere(
|
||||
(entry) => !_isSvgaEntityInUse(entry.value),
|
||||
orElse: () => videoItemCache.entries.first,
|
||||
);
|
||||
if (_isSvgaEntityInUse(removableEntry.value)) {
|
||||
videoItemCache.remove(removableEntry.key);
|
||||
videoItemCache[removableEntry.key] = removableEntry.value;
|
||||
while (_videoItemCache.length > _maxSvgaCacheEntries) {
|
||||
MapEntry<String, MovieEntity>? removableEntry;
|
||||
for (final entry in _videoItemCache.entries) {
|
||||
if (!_isCachedSvgaEntityInUse(entry.key, entry.value)) {
|
||||
removableEntry = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (removableEntry == null) {
|
||||
break;
|
||||
}
|
||||
videoItemCache.remove(removableEntry.key);
|
||||
_svgaRetainCounts.remove(removableEntry.key);
|
||||
_videoItemCache.remove(removableEntry.key);
|
||||
_disposeSvgaEntity(removableEntry.value);
|
||||
}
|
||||
}
|
||||
@ -833,13 +896,15 @@ class SCGiftVapSvgaManager {
|
||||
_preloadQueue.clear();
|
||||
_queuedPreloadPaths.clear();
|
||||
_activePreloadCount = 0;
|
||||
final entries = videoItemCache.entries.toList(growable: false);
|
||||
final entries = _videoItemCache.entries.toList(growable: false);
|
||||
for (final entry in entries) {
|
||||
final entity = entry.value;
|
||||
if (!includeCurrent && _isSvgaEntityInUse(entity)) {
|
||||
if (_isCachedSvgaEntityInUse(entry.key, entity) ||
|
||||
(!includeCurrent && _isSvgaEntityInUse(entity))) {
|
||||
continue;
|
||||
}
|
||||
videoItemCache.remove(entry.key);
|
||||
_svgaRetainCounts.remove(entry.key);
|
||||
_videoItemCache.remove(entry.key);
|
||||
_disposeSvgaEntity(entity);
|
||||
}
|
||||
_playablePathCache.clear();
|
||||
@ -849,6 +914,10 @@ class SCGiftVapSvgaManager {
|
||||
return identical(_rsc?.videoItem, entity);
|
||||
}
|
||||
|
||||
bool _isCachedSvgaEntityInUse(String path, MovieEntity entity) {
|
||||
return _isSvgaEntityInUse(entity) || (_svgaRetainCounts[path] ?? 0) > 0;
|
||||
}
|
||||
|
||||
void _disposeSvgaEntityIfUnused(MovieEntity entity) {
|
||||
if (_isSvgaEntityInUse(entity)) {
|
||||
return;
|
||||
|
||||
@ -51,6 +51,7 @@ class _SVGAHeadwearWidgetState extends State<SVGAHeadwearWidget>
|
||||
bool _isLoading = true;
|
||||
bool _isNetworkResource = false;
|
||||
bool _hasError = false;
|
||||
String? _retainedResource;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -84,8 +85,15 @@ class _SVGAHeadwearWidgetState extends State<SVGAHeadwearWidget>
|
||||
try {
|
||||
// 检查缓存
|
||||
MovieEntity? videoItem;
|
||||
final manager = SCGiftVapSvgaManager();
|
||||
final shouldRetain = _retainedResource != widget.resource;
|
||||
var retained = false;
|
||||
if (widget.useCache) {
|
||||
videoItem = SCGiftVapSvgaManager().videoItemCache[widget.resource];
|
||||
videoItem = manager.getCachedSvgaEntity(
|
||||
widget.resource,
|
||||
retain: shouldRetain,
|
||||
);
|
||||
retained = videoItem != null && shouldRetain;
|
||||
}
|
||||
|
||||
// 如果没有缓存,则进行解析
|
||||
@ -97,11 +105,23 @@ class _SVGAHeadwearWidgetState extends State<SVGAHeadwearWidget>
|
||||
videoItem.autorelease = false;
|
||||
// 存入缓存
|
||||
if (widget.useCache) {
|
||||
SCGiftVapSvgaManager().videoItemCache[widget.resource] = videoItem;
|
||||
if (!mounted) {
|
||||
videoItem.dispose();
|
||||
return;
|
||||
}
|
||||
manager.cacheSvgaEntity(
|
||||
widget.resource,
|
||||
videoItem,
|
||||
retain: shouldRetain,
|
||||
);
|
||||
retained = shouldRetain;
|
||||
}
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
if (retained) {
|
||||
_replaceRetainedResource(widget.resource);
|
||||
}
|
||||
setState(() {
|
||||
_animationController?.videoItem = videoItem;
|
||||
_isLoading = false;
|
||||
@ -164,13 +184,34 @@ class _SVGAHeadwearWidgetState extends State<SVGAHeadwearWidget>
|
||||
void reload() {
|
||||
if (widget.useCache) {
|
||||
// 清除缓存项
|
||||
SCGiftVapSvgaManager().videoItemCache.remove(widget.resource);
|
||||
SCGiftVapSvgaManager().removeCachedSvgaEntity(widget.resource);
|
||||
}
|
||||
_loadAnimation();
|
||||
}
|
||||
|
||||
void _replaceRetainedResource(String resource) {
|
||||
final previous = _retainedResource;
|
||||
if (previous == resource) {
|
||||
return;
|
||||
}
|
||||
if (previous != null) {
|
||||
SCGiftVapSvgaManager().releaseCachedSvgaEntity(previous);
|
||||
}
|
||||
_retainedResource = resource;
|
||||
}
|
||||
|
||||
void _releaseRetainedResource() {
|
||||
final resource = _retainedResource;
|
||||
if (resource == null) {
|
||||
return;
|
||||
}
|
||||
_retainedResource = null;
|
||||
SCGiftVapSvgaManager().releaseCachedSvgaEntity(resource);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_releaseRetainedResource();
|
||||
stop();
|
||||
_animationController?.dispose();
|
||||
super.dispose();
|
||||
|
||||
@ -270,6 +270,7 @@ class _RoomEntranceWidgetState extends State<RoomEntranceWidget>
|
||||
bool _isLoading = false;
|
||||
bool _hasError = false;
|
||||
String? _currentResource;
|
||||
String? _retainedResource;
|
||||
|
||||
// 用于存储SVGAImage组件的key,以便刷新占位符
|
||||
GlobalKey _svgaKey = GlobalKey();
|
||||
@ -354,9 +355,13 @@ class _RoomEntranceWidgetState extends State<RoomEntranceWidget>
|
||||
try {
|
||||
final isNetworkResource = resource.startsWith('http');
|
||||
MovieEntity? videoItem;
|
||||
final manager = SCGiftVapSvgaManager();
|
||||
final shouldRetain = _retainedResource != resource;
|
||||
var retained = false;
|
||||
|
||||
if (widget.useCache) {
|
||||
videoItem = SCGiftVapSvgaManager().videoItemCache[resource];
|
||||
videoItem = manager.getCachedSvgaEntity(resource, retain: shouldRetain);
|
||||
retained = videoItem != null && shouldRetain;
|
||||
}
|
||||
|
||||
if (videoItem == null) {
|
||||
@ -367,11 +372,19 @@ class _RoomEntranceWidgetState extends State<RoomEntranceWidget>
|
||||
videoItem.autorelease = false;
|
||||
|
||||
if (widget.useCache) {
|
||||
SCGiftVapSvgaManager().videoItemCache[resource] = videoItem;
|
||||
if (!mounted) {
|
||||
videoItem.dispose();
|
||||
return;
|
||||
}
|
||||
manager.cacheSvgaEntity(resource, videoItem, retain: shouldRetain);
|
||||
retained = shouldRetain;
|
||||
}
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
if (retained) {
|
||||
_replaceRetainedResource(resource);
|
||||
}
|
||||
// 应用动态数据(文本、图片替换)
|
||||
await _applyDynamicData(videoItem, dynamicData);
|
||||
|
||||
@ -553,7 +566,7 @@ class _RoomEntranceWidgetState extends State<RoomEntranceWidget>
|
||||
void reload() {
|
||||
if (_currentResource != null) {
|
||||
if (widget.useCache) {
|
||||
SCGiftVapSvgaManager().videoItemCache.remove(_currentResource);
|
||||
SCGiftVapSvgaManager().removeCachedSvgaEntity(_currentResource!);
|
||||
}
|
||||
|
||||
_loadAnimation(
|
||||
@ -566,6 +579,7 @@ class _RoomEntranceWidgetState extends State<RoomEntranceWidget>
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_releaseRetainedResource();
|
||||
stop();
|
||||
_animationController?.dispose();
|
||||
// 从队列管理器中移除当前播放器
|
||||
@ -573,6 +587,26 @@ class _RoomEntranceWidgetState extends State<RoomEntranceWidget>
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _replaceRetainedResource(String resource) {
|
||||
final previous = _retainedResource;
|
||||
if (previous == resource) {
|
||||
return;
|
||||
}
|
||||
if (previous != null) {
|
||||
SCGiftVapSvgaManager().releaseCachedSvgaEntity(previous);
|
||||
}
|
||||
_retainedResource = resource;
|
||||
}
|
||||
|
||||
void _releaseRetainedResource() {
|
||||
final resource = _retainedResource;
|
||||
if (resource == null) {
|
||||
return;
|
||||
}
|
||||
_retainedResource = null;
|
||||
SCGiftVapSvgaManager().releaseCachedSvgaEntity(resource);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// 显示加载状态
|
||||
|
||||
@ -57,6 +57,7 @@ class _SCNetworkSvgaWidgetState extends State<SCNetworkSvgaWidget>
|
||||
|
||||
late final SVGAAnimationController _controller;
|
||||
String? _loadedResource;
|
||||
String? _retainedResource;
|
||||
bool _hasError = false;
|
||||
|
||||
@override
|
||||
@ -82,6 +83,7 @@ class _SCNetworkSvgaWidgetState extends State<SCNetworkSvgaWidget>
|
||||
Future<void> _loadResource() async {
|
||||
final resource = widget.resource.trim();
|
||||
if (resource.isEmpty || !SCNetworkSvgaWidget.isSvga(resource)) {
|
||||
_releaseRetainedResource();
|
||||
setState(() {
|
||||
_hasError = true;
|
||||
_loadedResource = null;
|
||||
@ -96,23 +98,39 @@ class _SCNetworkSvgaWidgetState extends State<SCNetworkSvgaWidget>
|
||||
|
||||
try {
|
||||
_debugSvgaOnce(_loggedLoadingResources, 'loading', resource);
|
||||
final cache = SCGiftVapSvgaManager().videoItemCache;
|
||||
var movieEntity = cache[resource];
|
||||
final manager = SCGiftVapSvgaManager();
|
||||
final shouldRetain = _retainedResource != resource;
|
||||
var movieEntity = manager.getCachedSvgaEntity(
|
||||
resource,
|
||||
retain: shouldRetain,
|
||||
);
|
||||
var retained = movieEntity != null && shouldRetain;
|
||||
if (movieEntity == null) {
|
||||
movieEntity =
|
||||
resource.startsWith("http")
|
||||
? await SVGAParser.shared.decodeFromURL(resource)
|
||||
: await SVGAParser.shared.decodeFromAssets(resource);
|
||||
movieEntity.autorelease = false;
|
||||
cache[resource] = movieEntity;
|
||||
if (!mounted || widget.resource.trim() != resource) {
|
||||
movieEntity.dispose();
|
||||
return;
|
||||
}
|
||||
manager.cacheSvgaEntity(resource, movieEntity, retain: shouldRetain);
|
||||
retained = shouldRetain;
|
||||
}
|
||||
if (widget.movieConfigurer != null) {
|
||||
movieEntity.dynamicItem.reset();
|
||||
await widget.movieConfigurer!(movieEntity);
|
||||
}
|
||||
if (!mounted || widget.resource.trim() != resource) {
|
||||
if (retained) {
|
||||
manager.releaseCachedSvgaEntity(resource);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (retained) {
|
||||
_replaceRetainedResource(resource);
|
||||
}
|
||||
setState(() {
|
||||
_loadedResource = resource;
|
||||
_controller.videoItem = movieEntity;
|
||||
@ -157,8 +175,29 @@ class _SCNetworkSvgaWidgetState extends State<SCNetworkSvgaWidget>
|
||||
}
|
||||
}
|
||||
|
||||
void _replaceRetainedResource(String resource) {
|
||||
final previous = _retainedResource;
|
||||
if (previous == resource) {
|
||||
return;
|
||||
}
|
||||
if (previous != null) {
|
||||
SCGiftVapSvgaManager().releaseCachedSvgaEntity(previous);
|
||||
}
|
||||
_retainedResource = resource;
|
||||
}
|
||||
|
||||
void _releaseRetainedResource() {
|
||||
final resource = _retainedResource;
|
||||
if (resource == null) {
|
||||
return;
|
||||
}
|
||||
_retainedResource = null;
|
||||
SCGiftVapSvgaManager().releaseCachedSvgaEntity(resource);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_releaseRetainedResource();
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.6.0+160
|
||||
version: 1.6.1+161
|
||||
|
||||
|
||||
environment:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user