플러터 IOS 로그인 deep link 에러

kakao_flutter_sdk_user 1.5.0


안녕하세요 플러터로 앱 개발 중 에러가 발생해서 확인 요청드립니다
안드로이드에서는 정상 동작하나 iOS에서는 로그인 이후 아래와 같은 에러가 발생합니다

https://developers.kakao.com/docs/latest/ko/getting-started/sdk-flutter#setup-scheme-ios
링크 가이드에 따라서 설정도 동일하게 했는데 문제가 발생합니다!

1.4.3에서는 정상 동작하는데 1.5.0으로 버전을 올리면 문제가 생기네요 확인 후 답변 부탁드립니다

error

Deep Link does not contain valid required params. URL params: {
    code = "5NTcoXRMt6H4okjZyLn8-7u_qXdVxVPagl3xkHd1M99Dcv0-B8EANQvsz6XiPb1TkKggBgo9dNkAAAGKg8azFg";
}

동일한 문제 발생하여 댓글 남깁니다.
저같은 경우는 ios deep link 사용을 위해

<key>FlutterDeepLinkingEnabled</key>
<false/>

설정 해둔 상태이며, 위 deeplink 설정을 false로 하면 동작에 문제는 없으나, 딥링크가 동작 하지 않아… 해결이 필요한 상태입니다.

1개의 좋아요

@leo.won 안녕하세요. 플러터에서 딥링크를 구현할 수 있는 방법이 다양하다보니 말씀주신 내용만으로는 정확하게 어떤 상황인지 파악하기가 어렵습니다ㅠㅠ 딥링크 구현부 코드, 사용하는 패키지, 링크 주소, 재현 영상 등을 추가로 알려주시면 이슈파악하는데 큰 도움이 될 것 같습니다. 또한 커스텀 스킴을 사용했는지 애플의 유니버셜 링크를 사용한건지 등의 정보도 같이 전달 부탁드립니다. 그리고 앱이 실행 중인지 여부에 따라 딥링크 동작 방식이 다르기 때문에 어떤 경우에 이슈가 발생하는지도 알려주시면 감사하겠습니다. ex - 앱 종료 상태에서 딥링크를 통해 앱을 실행시키는 경우, 앱이 백그라운드에서 실행 중이고 딥링크를 사용해 앱으로 전환하는 경우

@junddao 안녕하세요 위의 답변에서 말씀드렸듯이 플러터에서 딥링크를 구현할 수 있는 방법이 다양하다보니 말씀주신 내용만으로는 어떤 상황인지 파악하기가 어렵습니다. 위 답변 확인 후 조금 더 구체적으로 설명 부탁드리겠습니다.

확인이 늦었습니다.

flutter deep link 구현 후 kakao에서 넘어오는

kakao64917f18…f2cd31360576b://oauth?code=JctSzqf_sTX83ox5lIb1_hYi …

요녀석을 go_router 에서 받아먹고 있네요.
flutter 코드에서 /?code=JctSzqf_sTX83ox5lIb1_hYiuPz2we … 요녀석을 받아 먹어서 예외처리 해둔 상태입니다.

  • kakao_flutter_sdk: ^1.5.0
  • Flutter 3.13.4

@junddao
go_router에서 kakao${app_key} 스킴을 가로챈다는 현상자체가 잘 이해가 가지 않는데요, 조금 번거로우시더라도 이슈 재현되는 간단한 샘플 프로젝트 만들어서 공유해주실 수 있을까요? (혹은 현재 프로젝트를 저에게 개인메시지로 보내주셔도 좋습니다)

전달해주신 내용을 바탕으로 직접 테스트했을 때는 이슈가 재현되지 않고, 현상에 대해서 잘 이해가 가지 않아서 원인 파악이 어려운 상태입니다ㅠㅠ

안녕하세요 1년이 지난 글이네요.
저희도 현재 동일한 현상이 발생하고 있어 글을 남깁니다.

go_router 패키지를 보면 redirect라는 부분이 있습니다. 보통은 이 부분을 페이지 이동 시 로그인 여부를 측정한다던가의 액션을 취한 뒤 다른 링크로 보내던, 원래 링크로 보내던 하는 역할로 쓰더라고요.
스크린샷 2024-09-11 22.14.40

그런데 카카오 로그인 후 저희 앱을 호출할 때 deeplink를 통해 호출 시, 여기서 일반적인 경우라면 앱의 원래 페이지로 돌아와 이후 액션 처리를 진행해야 하는데, 여기서 go_router의 redirect를 실행해버려서 의도치않게 페이지 이동이 진행되어 버립니다.

테스트로 go_router를 제외하고 해보니, 원래 카카오 로그인 액션대로 작동하는 것을 확인하였습니다.

글을 쓰신 분께도 궁금한게, 해결이 되었으니 더이상 글을 남기지 않으셨을텐데 어떻게 해결하신 것인지 궁금합니다!

감사합니다 :slight_smile:

@geniusk 안녕하세요

사용하는 sdk 버전, 이슈 발생하는 플랫폼 (Android / iOS / Web), 로그인 코드, 이슈 상황에서의 로그 첨부 부탁드리겠습니다.
추가로 GoRouter 설정도 공유해주시면 이슈 확인하는데 도움이 될 것 같아요

안녕하세요

SDK버전: 1.9.5
이슈 발생 플랫폼: Android / iOS
로그인 코드는 예제와 동일합니다.
https://developers.kakao.com/docs/latest/ko/kakaologin/flutter#kakaologin-sample

로그로 보면

  1. UserApi.instance.loginWithKakaoTalk(); 호출
  2. 카카오 측에서 딥링크로 kakaoec…00d86://oauth/?code=b8aS1U…-2W8wW6V7rJg 호출
  3. 자사 앱 실행
  4. 1번 아래 코드 실행하지 않고, GoRouter에 redirect 로직을 타버림 (이때 redirect 설정이 없으면 기본으로 return null을 시켜서 original link인 루트로 가버립니다. 이전 루트는 /abc 였지만 그냥 루트로 가버리는 현상 발생)

위 절차대로 흘러가 4번에서 문제가 발생하고 있습니다.
GoRouter 버전은 14.2.7 이며, 특별히 따로 설정한 부분은 없고, initialLocation이 /abc입니다.

빠른 답변 감사합니다

추석 연휴가 끼어있어서 답변이 조금 늦었습니다

말씀하신 내용으로 아래와 같이 샘플 코드 작성해서 구현해봤는데요, 이슈가 재현되지 않고 정상적으로 동작하는 것을 확인했습니다.

조금 번거로우시더라도 샘플 프로젝트를 만들어서 kakao_flutter_sdk와 go_router 의 의존성만 추가해서 구현했을 때 이슈가 재현되는지 확인부탁드리고, 여전히 이슈가 발생한다면 구현하신 코드 첨부 부탁드리겠습니다.

참고로 제가 테스트한 환경은 kakao_flutter_sdk 1.9.5 버전, go_router 14.2.7 버전입니다.

main.dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:go_router_login_error/test.dart';
import 'package:kakao_flutter_sdk/kakao_flutter_sdk.dart';

void main() {
  KakaoSdk.init(nativeAppKey: 'NATIVE_APP_KEY'); // 실제 앱 키 입력

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final _router = GoRouter(
    initialLocation: '/home',
    routes: [
      GoRoute(
        path: '/home',
        builder: (_, __) => const MyHomePage(title: 'Flutter Demo Home Page'),
        routes: [GoRoute(path: 'test', builder: (_, __) => const TestPage())],
        redirect: (BuildContext context, GoRouterState state) {
          if (state.uri.scheme.toString() == 'https' ||
              state.uri.scheme.toString() == 'applinks') {
            print('deepLink O');
          } else {
            print('deepLink X');
          }
          print(state.uri.toString());

          return null;
        },
      )
    ],
  );

  MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Home',
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          context.go("/home/test");
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

test.dart

import 'package:flutter/material.dart';
import 'package:kakao_flutter_sdk/kakao_flutter_sdk.dart';

class TestPage extends StatelessWidget {
  const TestPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Test Page')),
      body: const Center(
        child: Text('Test'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          try {
            await UserApi.instance.loginWithKakaoTalk();
            ScaffoldMessenger.of(context)
                .showSnackBar(SnackBar(content: Text('Login Success')));
          } catch (e) {
            ScaffoldMessenger.of(context)
                .showSnackBar(SnackBar(content: Text('Login Error: $e')));
          }
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}