feat: 集成 Apple Sign-In + iOS 上线准备
- 后端新增 Apple 登录端点 /api/auth/apple-login - 新增 AppleTokenValidator 验证 IdentityToken - User 实体添加 AppleUserId 字段,Phone 改为可空 - 前端添加 sign_in_with_apple 依赖和 Apple 登录按钮 - 统一 Bundle ID 为 com.datalumina.YYA,显示名称为小脉健康 - 配置 DEVELOPMENT_TEAM 和 Sign in with Apple Entitlements - 补充 NSCamera/NSPhotoLibrary 权限描述 - 生产 API 地址改为 https://erpapi.datalumina.cn/xiaomai - Flutter 升级至 3.44.6 / Dart 3.12.2 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
|
||||
import '../../core/app_colors.dart';
|
||||
import '../../core/navigation_provider.dart';
|
||||
import '../../providers/auth_provider.dart';
|
||||
@@ -63,6 +66,70 @@ class _LoginPageState extends ConsumerState<LoginPage> {
|
||||
}
|
||||
}
|
||||
|
||||
// Apple 登录
|
||||
Future<void> _appleSignIn() async {
|
||||
if (_loading) return;
|
||||
setState(() {
|
||||
_loading = true;
|
||||
_error = null;
|
||||
_successMsg = null;
|
||||
});
|
||||
|
||||
try {
|
||||
final credential = await SignInWithApple.getAppleIDCredential(
|
||||
scopes: [
|
||||
AppleIDAuthorizationScopes.fullName,
|
||||
],
|
||||
webAuthenticationOptions: WebAuthenticationOptions(
|
||||
clientId: 'com.datalumina.YYA.signin',
|
||||
redirectUri: Uri.parse(
|
||||
'https://erpapi.datalumina.cn/xiaomai/api/auth/apple-login',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final identityToken = credential.identityToken;
|
||||
if (identityToken == null) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_loading = false;
|
||||
_error = 'Apple 登录未返回身份信息,请重试';
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final name = credential.givenName != null && credential.familyName != null
|
||||
? '${credential.familyName}${credential.givenName}'
|
||||
: null;
|
||||
|
||||
final err = await ref.read(authProvider.notifier).appleLogin(
|
||||
identityToken,
|
||||
credential.authorizationCode,
|
||||
name,
|
||||
);
|
||||
if (mounted) {
|
||||
setState(() => _loading = false);
|
||||
if (err != null) {
|
||||
setState(() => _error = err);
|
||||
} else {
|
||||
_goHome();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_loading = false;
|
||||
if (e is SignInWithAppleAuthorizationException) {
|
||||
_error = 'Apple 登录已取消';
|
||||
} else {
|
||||
_error = 'Apple 登录失败: $e';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _submit() async {
|
||||
if (!_agreed) {
|
||||
final accepted = await _showAgreementDialog();
|
||||
@@ -489,6 +556,15 @@ class _LoginPageState extends ConsumerState<LoginPage> {
|
||||
label: _isLogin ? '登录' : '注册',
|
||||
onTap: _loading ? null : _submit,
|
||||
),
|
||||
// Apple 登录按钮(仅 iOS/macOS)
|
||||
if (_isLogin && (Platform.isIOS || Platform.isMacOS)) ...[
|
||||
const SizedBox(height: 20),
|
||||
SignInWithAppleButton(
|
||||
onPressed: _loading ? () {} : () { _appleSignIn(); },
|
||||
style: SignInWithAppleButtonStyle.whiteOutlined,
|
||||
height: 48,
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
GestureDetector(
|
||||
onTap: () => setState(() {
|
||||
|
||||
Reference in New Issue
Block a user