三、第一步:SDK 层(最底层,只负责 fluwx)

1️⃣ wechat_sdk_datasource.dart


import 'package:fluwx/fluwx.dart';

class WechatSdkDataSource {
  final Fluwx _fluwx;

  WechatSdkDataSource(this._fluwx);

  Future<bool> isInstalled() async {
    return await _fluwx.isWeChatInstalled;
  }

  Future<void> requestAuth() async {
    await _fluwx.authBy(
      which: NormalAuth(
        scope: 'snsapi_userinfo',
        state: 'login',
      ),
    );
  }

  void listenAuth(void Function(String code) onCode) {
    _fluwx.addSubscriber((resp) {
      if (resp is WeChatAuthResponse && resp.isSuccessful) {
        onCode(resp.code!);
      }
    });
  }
}

📌 注意

  • ❌ 不调后端

  • ❌ 不存 token

  • ❌ 不跳页面

👉 这里只和 fluwx 打交道


四、Domain 层(真正的业务核心)

2️⃣ wechat_auth_result.dart


class WechatAuthResult {
  final bool isNewUser;
  final String? accessToken;
  final String? openId;

  WechatAuthResult({
    required this.isNewUser,
    this.accessToken,
    this.openId,
  });
}

3️⃣ wechat_auth_repository.dart(抽象)


abstract class WechatAuthRepository {
  Future<WechatAuthResult> loginByCode(String code);
}

五、Data → Repository 实现(真正调你后端)

4️⃣ wechat_auth_repository_impl.dart


import '../../domain/entity/wechat_auth_result.dart';
import '../../domain/repository/wechat_auth_repository.dart';
import '../../http/http.dart';

class WechatAuthRepositoryImpl implements WechatAuthRepository {
  @override
  Future<WechatAuthResult> loginByCode(String code) async {
    final res = await HttpUtil.dio.post(
      "/api/auth/wechat/login",
      data: {"code": code},
    );

    final data = res.data;

    if (data["isNewUser"] == true) {
      return WechatAuthResult(
        isNewUser: true,
        openId: data["openId"],
      );
    }

    return WechatAuthResult(
      isNewUser: false,
      accessToken: data["accessToken"],
    );
  }
}

📌 关键点

  • Flutter 不再关心微信细节

  • 后端是唯一微信接口调用者


六、UseCase(业务动作封装)

5️⃣ wechat_login_usecase.dart


import '../entity/wechat_auth_result.dart';
import '../repository/wechat_auth_repository.dart';

class WechatLoginUseCase {
  final WechatAuthRepository repository;

  WechatLoginUseCase(this.repository);

  Future<WechatAuthResult> execute(String code) {
    return repository.loginByCode(code);
  }
}

👉 这一步的价值:
以后你要接 Apple / Google 登录,只换 UseCase


七、Presentation 层(UI & 跳转)

6️⃣ wechat_login_controller.dart(GetX / Bloc 都行)


import 'package:get/get.dart';
import '../../domain/usecase/wechat_login_usecase.dart';
import '../../domain/entity/wechat_auth_result.dart';
import '../pages/wechat_bind_phone_page.dart';
import '../../main.dart';

class WechatLoginController extends GetxController {
  final WechatLoginUseCase useCase;

  WechatLoginController(this.useCase);

  Future<void> handleWechatCode(String code) async {
    final result = await useCase.execute(code);

    if (result.isNewUser) {
      Get.to(() => WechatBindPhonePage(
            openId: result.openId!,
          ));
    } else {
      storage.write("token", result.accessToken);
      Get.offAll(() => const MainPage());
    }
  }
}

📌 注意

  • 跳转只在 Presentation 层

  • Domain 层完全不依赖 Flutter


八、初始化 & 注入(你现在 registerApi 的正确位置)

7️⃣ wechat_initializer.dart


import 'package:fluwx/fluwx.dart';

class WechatInitializer {
  static Future<void> init() async {
    await Fluwx().registerApi(
      appId: "wx_xxxxx",
      universalLink: "https://xxxx.com/wechat/",
    );
  }
}

在 main():


void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await WechatInitializer.init();
  runApp(MyApp());
}

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐