ar_tourism_flutter_unity/lib/unity_page.dart
2025-05-14 18:24:12 +08:00

187 lines
5.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'unity_controller.dart';
class UnityPage extends StatefulWidget {
final String? token;
final String? sceneName;
const UnityPage({
Key? key,
this.sceneName = 'Main',
this.token,
}) : super(key: key);
@override
State<UnityPage> createState() => _UnityPageState();
}
class _UnityPageState extends State<UnityPage> with WidgetsBindingObserver {
// Unity通信通道
static const MethodChannel _channel = MethodChannel('com.example.ar_tourism_flutter_unity.unity');
bool _isLoading = true;
bool _hasError = false;
String _errorMessage = '';
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_setupMessageHandler();
_initializeUnity();
}
void _setupMessageHandler() {
_channel.setMethodCallHandler((call) async {
switch (call.method) {
case 'onUnityBackPressed':
print('接收到Unity返回请求');
Navigator.of(context).pop();
return true;
case 'onUnityClosed':
print('Unity已关闭');
if (mounted) Navigator.of(context).pop();
return true;
default:
return false;
}
});
}
Future<void> _initializeUnity() async {
setState(() {
_isLoading = true;
_hasError = false;
});
try {
// 初始化Unity
final bool initialized = await _channel.invokeMethod('initializeUnity') ?? false;
if (!initialized) {
throw Exception('Unity初始化失败');
}
// 检查权限
final bool hasPermissions = await _channel.invokeMethod('checkAndRequestPermissions') ?? false;
if (!hasPermissions) {
throw Exception('未获得必要权限');
}
// 启动Unity场景
await _channel.invokeMethod('start_unity', {
'returnToHome': true,
'token': widget.token ?? '',
'sceneName': widget.sceneName ?? 'Main',
});
setState(() {
_isLoading = false;
});
} catch (e) {
print('Unity启动错误: $e');
setState(() {
_isLoading = false;
_hasError = true;
_errorMessage = e.toString();
});
}
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
// 从后台恢复时可能需要重新初始化Unity
print('应用从后台恢复');
} else if (state == AppLifecycleState.paused) {
// 应用进入后台时可能需要暂停Unity
print('应用进入后台');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Stack(
children: [
// Unity视图或错误消息
if (_hasError)
Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.error_outline, size: 48, color: Colors.red),
SizedBox(height: 16),
Text(
'加载AR内容失败',
style: TextStyle(color: Colors.white, fontSize: 18),
),
SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Text(
_errorMessage,
style: TextStyle(color: Colors.white70, fontSize: 14),
textAlign: TextAlign.center,
),
),
SizedBox(height: 24),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('返回'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
),
],
),
)
else if (_isLoading)
Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
SizedBox(height: 16),
Text(
'正在加载AR内容...',
style: TextStyle(color: Colors.white, fontSize: 16),
),
],
),
),
// 返回按钮
SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Align(
alignment: Alignment.topLeft,
child: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.of(context).pop(),
),
),
),
),
],
),
);
}
@override
void dispose() {
// 清理资源
_channel.invokeMethod('closeUnity');
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
}