Flutter集成Genuin服务插件genuin_sdk的使用

Flutter集成Genuin服务插件genuin_sdk的使用

Genuin SDK包含品牌信息流、社区和群组等功能。

⬇️ 安装

在您的Flutter项目的pubspec.yaml文件中添加genuin_sdk依赖项:

dependencies:
  genuin_sdk: <latest_version>

Android

Android配置
  1. android/build.gradle文件中:
allprojects {
    repositories {
        google()
        mavenCentral()
        // 添加jitpack
        maven {
            setUrl("https://jitpack.io")
        }
    }
}
  1. android/app/build.gradle文件中:
android {
    defaultConfig {
        minSdk = 24
    }
}
  1. android/app/src/main/AndroidManifest.xml文件中:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <!-- 添加 tools:replace="android:label" -->
    <application android:label="genuin_sdk_example" android:icon="@mipmap/ic_launcher"
        tools:replace="android:label">

        <!-- 1. 如果想要处理深度链接,将启动模式改为singleTask
             2. 移除 android:taskAffinity=""
             3. 为了更好的SDK性能,使用 android:windowSoftInputMode="adjustPan"
             -->

        <activity android:name=".MainActivity" android:exported="true"
            android:launchMode="singleTask" android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true" android:windowSoftInputMode="adjustPan">
            <meta-data android:name="io.flutter.embedding.android.NormalTheme"
                android:resource="@style/NormalTheme" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
  1. 更改主题在android/app/src/main/res/values/styles.xml文件中:

我们的SDK使用Material组件,因此您需要使用Material主题,如以下示例所示:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 当OS的黑暗模式设置关闭时应用于Android窗口的主题 -->
    <style name="LaunchTheme" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge">
        <!-- 显示启动屏幕。当Flutter引擎绘制第一帧时自动移除 -->
        <item name="android:windowBackground">@drawable/launch_background</item>
    </style>
    <!-- 当进程启动时应用于Android窗口的主题。
         此主题确定Flutter UI初始化期间以及运行时窗口后面的颜色。
         这个主题仅从Flutter的Android嵌入版本V2开始使用。 -->
    <style name="NormalTheme" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge">
        <item name="android:windowBackground">?android:colorBackground</item>
    </style>
</resources>
  1. 创建android/app/proguard-rules.pro文件,并添加以下行:
# 添加项目特定的ProGuard规则
# 您可以使用build.gradle中的proguardFiles设置控制应用的配置文件集
#
# 更多详情,请访问
#   http://developer.android.com/guide/developing/tools/proguard.html

# 取消注释以保留调试堆栈跟踪的行号信息
#-keepattributes SourceFile,LineNumberTable

-keep class com.bumptech.glide.**{*;}
-keep public class * {
    public *;
    protected *;
}

# Retrofit进行反射时需要Signature和EnclosingMethod属性
-keepattributes Signature, InnerClasses, EnclosingMethod

# Retrofit进行反射时需要RuntimeVisibleAnnotations和RuntimeVisibleParameterAnnotations属性
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations

# 保持服务方法参数以优化
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* &lt;methods&gt;;
}

# 忽略用于构建工具的注解
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

# 忽略JSR 305注解,用于嵌入空值信息
-dontwarn javax.annotation.**

# 由NoClassDefFoundError try/catch保护,仅在类路径上使用
-dontwarn kotlin.Unit

# 仅由Kotlin使用的顶级函数
-dontwarn retrofit2.KotlinExtensions
-dontwarn java.lang.reflect.AnnotatedType
-dontwarn com.google.api.client.http.GenericUrl
-dontwarn com.google.api.client.http.HttpHeaders
-dontwarn com.google.api.client.http.HttpRequest
-dontwarn com.google.api.client.http.HttpRequestFactory
-dontwarn com.google.api.client.http.HttpResponse
-dontwarn com.google.api.client.http.HttpTransport
-dontwarn com.google.api.client.http.javanet.NetHttpTransport$Builder
-dontwarn com.google.api.client.http.javanet.NetHttpTransport
-dontwarn com.squareup.picasso.Picasso
-dontwarn com.squareup.picasso.RequestCreator
-dontwarn java.awt.image.BufferedImage
-dontwarn javax.imageio.ImageIO
-dontwarn org.joda.time.Instant
-dontwarn org.junit.Assert
-dontwarn org.slf4j.impl.StaticLoggerBinder
-dontwarn org.slf4j.impl.StaticMDCBinder
-dontwarn org.slf4j.impl.StaticMarkerBinder

# 使用R8全模式时,它看不到通过代理创建的Retrofit接口的子类型,并用null替换所有潜在值。显式保留这些接口可以防止这种情况。
-if interface * { @retrofit2.http.* &lt;methods&gt;; }
-keep,allowobfuscation interface &lt;1&gt;

##---------------Begin: proguard configuration for Gson  ----------
# Gson在工作时会存储类文件中的泛型类型信息。默认情况下,ProGuard会删除此类信息,因此在此处配置以保留所有信息。
-keepattributes Signature

# 对于使用Gson @Expose注解
-keepattributes *Annotation*

# Gson特定类
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }

# 应序列化/反序列化的应用程序类
-keep class com.begenuin.begenuin.data.model.** { &lt;fields&gt;; }
-keep class com.begenuin.begenuin.vo.** { &lt;fields&gt;; }

# RenderScript
-keepclasseswithmembernames class * {
native &lt;methods&gt;;
}
-keep class androidx.renderscript.** { *; }

-keepattributes *Annotation*

-keep class com.giphy.sdk.core.models.** { *; }
-keep class com.giphy.sdk.ui.views.** { *; }

-keep public class * implements java.lang.reflect.Type

-keep class com.google.mediapipe.solutioncore.** {*;}
-keep class com.google.protobuf.** {*;}

-dontwarn com.begenuin.sdk.BR
-dontwarn com.google.android.play.core.splitcompat.SplitCompatApplication
-dontwarn com.google.android.play.core.splitinstall.SplitInstallManager
-dontwarn com.google.android.play.core.splitinstall.SplitInstallManagerFactory
-dontwarn com.google.android.play.core.splitinstall.SplitInstallRequest$Builder
-dontwarn com.google.android.play.core.splitinstall.SplitInstallRequest
-dontwarn com.google.android.play.core.splitinstall.SplitInstallStateUpdatedListener
-dontwarn com.google.android.play.core.tasks.OnFailureListener
-dontwarn com.google.android.play.core.tasks.OnSuccessListener
-dontwarn com.google.android.play.core.tasks.Task
-dontwarn com.google.mediapipe.proto.CalculatorProfileProto$CalculatorProfile
-dontwarn com.google.mediapipe.proto.GraphTemplateProto$CalculatorGraphTemplate
-dontwarn javax.lang.model.AnnotatedConstruct
-dontwarn javax.lang.model.SourceVersion
-dontwarn javax.lang.model.element.AnnotationMirror
-dontwarn javax.lang.model.element.AnnotationValue
-dontwarn javax.lang.model.element.AnnotationValueVisitor
-dontwarn javax.lang.model.element.Element
-dontwarn javax.lang.model.element.ElementKind
-dontwarn javax.lang.model.element.ElementVisitor
-dontwarn javax.lang.model.element.ExecutableElement
-dontwarn javax.lang.model.element.Name
-dontwarn javax.lang.model.element.NestingKind
-dontwarn javax.lang.model.element.PackageElement
-dontwarn javax.lang.model.element.QualifiedNameable
-dontwarn javax.lang.model.element.TypeElement
-dontwarn javax.lang.model.element.TypeParameterElement
-dontwarn javax.lang.model.element.VariableElement
-dontwarn javax.lang.model.type.ArrayType
-dontwarn javax.lang.model.type.DeclaredType
-dontwarn javax.lang.model.type.ErrorType
-dontwarn javax.lang.model.type.ExecutableType
-dontwarn javax.lang.model.type.IntersectionType
-dontwarn javax.lang.model.type.NoType
-dontwarn javax.lang.model.type.NullType
-dontwarn javax.lang.model.type.PrimitiveType
-dontwarn javax.lang.model.type.TypeKind
-dontwarn javax.lang.model.type.TypeMirror
-dontwarn javax.lang.model.type.TypeVariable
-dontwarn javax.lang.model.type.TypeVisitor
-dontwarn javax.lang.model.type.WildcardType
-dontwarn javax.lang.model.util.AbstractElementVisitor8
-dontwarn javax.lang.model.util.ElementFilter
-dontwarn javax.lang.model.util.Elements
-dontwarn javax.lang.model.util.SimpleAnnotationValueVisitor8
-dontwarn javax.lang.model.util.SimpleElementVisitor8
-dontwarn javax.lang.model.util.SimpleTypeVisitor8
-dontwarn javax.lang.model.util.Types
-dontwarn javax.tools.Diagnostic$Kind
-dontwarn javax.tools.JavaFileObject$Kind
-dontwarn javax.tools.JavaFileObject
-dontwarn javax.tools.SimpleJavaFileObject
  1. 想要覆盖我们的默认加载器

我们使用Lottie动画作为加载器。您可以将自定义的Lottie动画加载器命名为loader_mix.json并放在android/app/src/main/res/raw文件夹中。确保您使用的是提供的名称。

快速开始

  1. 初始化SDK
import android.content.Intent
import android.os.Bundle
import com.begenuin.genuin_sdk.GenuinSdkPlugin
import io.flutter.embedding.android.FlutterFragmentActivity

// 这里我们需要使用FlutterFragmentActivity而不是FlutterActivity
class MainActivity : FlutterFragmentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        GenuinSdkPlugin.initSDK(this@MainActivity, "YOUR_API_KEY")
    }
}
  1. 处理深度链接

android/app/src/main/AndroidManifest.xml文件中:

<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTask"
    android:theme="@style/LaunchTheme"
    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
    android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
    <meta-data android:name="io.flutter.embedding.android.NormalTheme"
        android:resource="@style/NormalTheme" />
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:host="YOUR_WHITE-LABELLED_DOMAIN" android:scheme="https" />
    </intent-filter>
</activity>
import android.content.Intent
import android.os.Bundle
import com.begenuin.genuin_sdk.GenuinSdkPlugin
import io.flutter.embedding.android.FlutterFragmentActivity

class MainActivity : FlutterFragmentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        GenuinSdkPlugin.initSDK(this@MainActivity, "YOUR_API_KEY")
        handleDeepLink(intent)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        handleDeepLink(intent)
    }

    private fun handleDeepLink(intent: Intent?) {
        intent?.data?.let {
            GenuinSdkPlugin.handleDeepLink(this@MainActivity, intent)
        }
    }
}

iOS

iOS配置

  1. ios/Podfile文件中:
# 取消注释此行以定义项目的全局平台
platform :ios, '13.0'

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
    if target.name == 'Giphy'
      `xcrun -sdk iphoneos bitcode_strip -r Pods/Giphy/GiphySDK/GiphyUISDK.xcframework/ios-arm64_armv7/GiphyUISDK.framework/GiphyUISDK -o Pods/Giphy/GiphySDK/GiphyUISDK.xcframework/ios-arm64_armv7/GiphyUISDK.framework/GiphyUISDK`
    end
    target.build_configurations.each do |config|
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
      config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
    end
  end
end

快速开始

  1. 初始化SDK
import Flutter
import UIKit
import genuin_sdk

@main
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GenuinSdkPlugin.initialize(apiKey: "YOUR_API_KEY", loaderName: "YOUR_LOTTIE_LOADER_NAME")
    // 我们使用Lottie动画作为加载器。您可以在应用资源中放置自定义Lottie动画加载器。初始化SDK时更新“YOUR_LOTTIE_LOADER_NAME”为您的加载器名称。

    GeneratedPluginRegistrant.register(with: self)
    // UINavigationController在原生组件中用于重定向目的
    if let flutterViewController: FlutterViewController = window?.rootViewController as? FlutterViewController {
        let navigationController = GenuinSdkPlugin.getGenuinNavigationController(rootViewController: flutterViewController)
        navigationController.setNavigationBarHidden(true, animated: false)
        window?.rootViewController = navigationController
        window?.makeKeyAndVisible()
    }
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}
  1. 处理深度链接

AppDelegate.swift文件中:

import Flutter
import UIKit
import genuin_sdk

@main
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
      GenuinSdkPlugin.initialize(apiKey: "YOUR_API_KEY", loaderName: "YOUR_LOTTIE_LOADER_NAME")
      GeneratedPluginRegistrant.register(with: self)
      if let flutterViewController: FlutterViewController = window?.rootViewController as? FlutterViewController {
          let navigationController = GenuinSdkPlugin.getGenuinNavigationController(rootViewController: flutterViewController)
          navigationController.setNavigationBarHidden(true, animated: false)
          window?.rootViewController = navigationController
          window?.makeKeyAndVisible()
      }
      return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  override func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) -> Bool {
        let result = GenuinSdkPlugin.flutterapplication(application, continue: userActivity, restorationHandler: restorationHandler)
        if GenuinSdkPlugin.handleDeepLink(dlURL: userActivity.webpageURL, controller: window?.rootViewController) {
            return true
        }
        return result
    }
}
  1. 处理推送通知

AppDelegate.swift文件中:

import Flutter
import UIKit
import genuin_sdk

@main
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
      GenuinSdkPlugin.initialize(apiKey: "YOUR_API_KEY", loaderName: "YOUR_LOTTIE_LOADER_NAME")
      UNUserNotificationCenter.current().delegate = self
      GeneratedPluginRegistrant.register(with: self)
      if let flutterViewController: FlutterViewController = window?.rootViewController as? FlutterViewController {
          let navigationController = GenuinSdkPlugin.getGenuinNavigationController(rootViewController: flutterViewController)
          navigationController.setNavigationBarHidden(true, animated: false)
          window?.rootViewController = navigationController
          window?.makeKeyAndVisible()
      }
      return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        print("\(userInfo )")
        completionHandler(.newData)
    }
    override func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void){
        let userInfo = notification.request.content.userInfo
        print("\(userInfo)")
        // 移除横幅以显示应用内通知
        if #available(iOS 14.0, *) {
            completionHandler([.banner, .list, .badge, .sound])
        } else {
            // 在早期版本上回退
            completionHandler([])
        }
    }
}

Flutter

  1. 加载轮播嵌入视图
import 'package:genuin_sdk/genuin_carousel_embed_view.dart';

[@override](/user/override)
Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      body: SizedBox(
        height: 300, // 根据需要调整高度
        width: MediaQuery.of(context).size.width, // 根据需要调整宽度
        child: const Carousel(
          embedId: "YOUR_EMBED_ID",
          uniqueId: "UNIQUE_ID",
          ssoToken: "YOUR_SSO_TOKEN",
          isShowProfileEnabled: false,
          isDirectDeepLinkEnabled: false,
        ),
      ),
    ),
  );
}

要暂停/恢复轮播视频

import 'package:genuin_sdk/genuin_sdk.dart';

setState(() {

    final _genuinSdkPlugin = GenuinSdk();
    
    // 添加您要暂停/恢复视频的轮播embedId/uniqueId。
    final carouselConfig = {
    'embedId': "YOUR_EMBED_ID",
    'uniqueId': "UNIQUE_ID"
    };
    
    // 恢复视频播放
    _genuinSdkPlugin.resumeCarousel(carouselConfig);
    
    // 暂停视频播放
    _genuinSdkPlugin.pauseCarousel(carouselConfig);

});

要根据需要配置嵌入参数,您可以传递以下值。

  • embedId = 您要加载的嵌入ID。
  • uniqueId = 这是一个可选参数。当我们在同一屏幕上显示相同的嵌入时,需要使用此唯一ID。对于同一嵌入ID在同一屏幕上多次显示,需要提供唯一ID。
  • ssoToken = 这是一个可选参数。为了在应用中实现嵌入SSO,您应该传递“YOUR_SSO_TOKEN”。
  • interactionDeepLink = 这是一个可选参数。您可以在此参数中传递一个深度链接URL。如果提供了深度链接URL,则全屏视图中的所有交互/点击将重定向到给定的深度链接URL。如果没有传递,则将按常规流程工作。如果不正确,则用户不会被重定向。
  • isDirectDeepLinkEnabled = 这是一个可选布尔参数,默认值为false。如果此参数为真,则全屏视图中的所有交互/点击将重定向到与视频关联的白标应用中的特定视频,并且“interactionDeepLink”参数的值将被忽略。如果没有传递,则将按常规流程工作。
  • 注意:要使用isDirectDeepLinkEnabled参数,您必须首先对您的域进行白标,并在您要重定向此视频的主应用中集成深度链接部分。
  • isShowProfileEnabled = 这是一个可选布尔参数,默认值为false。如果此参数为真并且用户已登录,则全屏视图(右上角)将显示个人资料图片。单击个人资料图片,用户将看到帐户设置和登出选项。
  1. 加载标准墙嵌入视图
import 'package:genuin_sdk/genuin_standard_wall_view.dart';

[@override](/user/override)
Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      body: SizedBox(
        height: MediaQuery.of(context).size.height, // 根据需要调整高度
        width: MediaQuery.of(context).size.width, // 根据需要调整宽度
        child: const StandardWall(
          embedId: "YOUR_EMBED_ID",
          uniqueId: "UNIQUE_ID",
          ssoToken: "YOUR_SSO_TOKEN",
          isShowProfileEnabled: false,
          isDirectDeepLinkEnabled: false,
        ),
      ),
    ),
  );
}

要暂停/恢复标准墙视频

import 'package:genuin_sdk/genuin_sdk.dart';

setState(() {

    final _genuinSdkPlugin = GenuinSdk();
    
    // 添加您要暂停/恢复视频的标准墙embedId/uniqueId。
    final standardWallConfig = {
    'embedId': "YOUR_EMBED_ID",
    'uniqueId': "UNIQUE_ID"
    };
    
    // 恢复视频播放
    _genuinSdkPlugin.resumeStandWall(standardWallConfig);
    
    // 暂停视频播放
    _genuinSdkPlugin.pauseStandWall(standardWallConfig);

});

要根据需要配置嵌入参数,您可以传递以下值。

  • embedId = 您要加载的嵌入ID。
  • uniqueId = 这是一个可选参数。当我们在同一屏幕上显示相同的嵌入时,需要使用此唯一ID。对于同一嵌入ID在同一屏幕上多次显示,需要提供唯一ID。
  • ssoToken = 这是一个可选参数。为了在应用中实现嵌入SSO,您应该传递“YOUR_SSO_TOKEN”。
  • interactionDeepLink = 这是一个可选参数。您可以在此参数中传递一个深度链接URL。如果提供了深度链接URL,则全屏视图中的所有交互/点击将重定向到给定的深度链接URL。如果没有传递,则将按常规流程工作。如果不正确,则用户不会被重定向。
  • isDirectDeepLinkEnabled = 这是一个可选布尔参数,默认值为false。如果此参数为真,则全屏视图中的所有交互/点击将重定向到与视频关联的白标应用中的特定视频,并且“interactionDeepLink”参数的值将被忽略。如果没有传递,则将按常规流程工作。
  • 注意:要使用isDirectDeepLinkEnabled参数,您必须首先对您的域进行白标,并在您要重定向此视频的主应用中集成深度链接部分。
  • isShowProfileEnabled = 这是一个可选布尔参数,默认值为false。如果此参数为真并且用户已登录,则全屏视图(右上角)将显示个人资料图片。单击个人资料图片,用户将看到帐户设置和登出选项。
  1. 加载全屏嵌入视图
import 'package:genuin_sdk/genuin_feed_embed_view.dart';

[@override](/user/override)
Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      body: SizedBox(
        height: MediaQuery.of(context).size.height, // 根据需要调整高度
        width: MediaQuery.of(context).size.width, // 根据需要调整宽度
        child: const Feed(
          embedId: "YOUR_EMBED_ID",
          uniqueId: "UNIQUE_ID",
          ssoToken: "YOUR_SSO_TOKEN",
          isShowProfileEnabled: false,
          isDirectDeepLinkEnabled: false,
        ),
      ),
    ),
  );
}

要暂停/恢复全屏视图中的视频

import 'package:genuin_sdk/genuin_sdk.dart';

setState(() {

    final _genuinSdkPlugin = GenuinSdk();
    
    // 添加您要暂停/恢复视频的全屏视图embedId/uniqueId。
    final feedConfig = {
    'embedId': "YOUR_EMBED_ID",
    'uniqueId': "UNIQUE_ID"
    };
    
    // 恢复视频播放
    _genuinSdkPlugin.resumeFeed(feedConfig);
    
    // 暂停视频播放
    _genuinSdkPlugin.pauseFeed(feedConfig);

});

要根据需要配置嵌入参数,您可以传递以下值。

  • embedId = 您要加载的嵌入ID。
  • uniqueId = 这是一个可选参数。当我们在同一屏幕上显示相同的嵌入时,需要使用此唯一ID。对于同一嵌入ID在同一屏幕上多次显示,需要提供唯一ID。
  • ssoToken = 这是一个可选参数。为了在应用中实现嵌入SSO,您应该传递“YOUR_SSO_TOKEN”。
  • interactionDeepLink = 这是一个可选参数。您可以在此参数中传递一个深度链接URL。如果提供了深度链接URL,则全屏视图中的所有交互/点击将重定向到给定的深度链接URL。如果没有传递,则将按常规流程工作。如果不正确,则用户不会被重定向。
  • isDirectDeepLinkEnabled = 这是一个可选布尔参数,默认值为false。如果此参数为真,则全屏视图中的所有交互/点击将重定向到与视频关联的白标应用中的特定视频,并且“interactionDeepLink”参数的值将被忽略。如果没有传递,则将按常规流程工作。
  • 注意:要使用isDirectDeepLinkEnabled参数,您必须首先对您的域进行白标,并在您要重定向此视频的主应用中集成深度链接部分。
  • isShowProfileEnabled = 这是一个可选布尔参数,默认值为false。如果此参数为真并且用户已登录,则全屏视图(右上角)将显示个人资料图片。单击个人资料图片,用户将看到帐户设置和登出选项。
  1. 加载HomeFeed视图(Android特定)
import 'package:genuin_sdk/genuin_feed_view.dart';

[@override](/user/override)
Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      body: HomeFeed(),
    ),
  );
}
  1. 处理推送通知

前提条件

创建Firebase项目并将其集成到您的应用中,遵循Firebase文档

步骤

  1. 在lib文件夹中创建firebase_options.dart文件,并添加以下详细信息:
import 'package:firebase_core/firebase_core.dart';

class DefaultFirebaseOptions {
  static FirebaseOptions get currentPlatform {
    if (Platform.isAndroid) {
      return const FirebaseOptions(
        apiKey: 'YOUR-ANDROID-API-KEY',
        appId: 'YOUR-ANDROID-APP-ID',
        messagingSenderId: 'YOUR-SENDER-ID',
        projectId: 'YOUR-PROJECT-ID',
        storageBucket: 'YOUR-STORAGE-BUCKET',
      );
    } else {
      return const FirebaseOptions(
        apiKey: 'YOUR-IOS-API-KEY',
        appId: 'YOUR-IOS-APP-ID',
        messagingSenderId: 'YOUR-SENDER-ID',
        projectId: 'YOUR-PROJECT-ID',
        storageBucket: 'YOUR-STORAGE-BUCKET',
      );
    }
  }
}
  1. 处理后台/前台通知

注意:对于Android,您需要提供小的通知图标作为“icon”键以处理前台通知。该图标需要同时存在于您的Flutter项目和Android文件夹中。

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:genuin_sdk/genuin_sdk.dart';
import 'firebase_options.dart';

// 当应用在后台收到推送消息时调用此方法
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
}

final _genuinSdkPlugin = GenuinSdk();

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    name: 'YOUR_FIREBASE_PROJECT_NAME',
    options: DefaultFirebaseOptions.currentPlatform,
  );
  final messaging = FirebaseMessaging.instance;

  // 请求推送通知权限
  final settings = await messaging.requestPermission(
    alert: true,
    announcement: false,
    badge: true,
    carPlay: false,
    criticalAlert: false,
    provisional: false,
    sound: true,
  );

  // 如果权限被授予,则获取Firebase令牌并将其注册到Genuin SDK
  if (settings.authorizationStatus == AuthorizationStatus.authorized) {
    String? token = await messaging.getToken();
    if (token != null) {
      await _genuinSdkPlugin.registerFCMToken(token);
    }
  }

  // 检查打开应用的初始通知
  RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();
  if (initialMessage != null) {
    // 处理导航或操作
    final notificationData = {
      'title': initialMessage.notification?.title,
      'body': initialMessage.notification?.body,
      'data': initialMessage.data,
    };
    var willHandleNotification = await _genuinSdkPlugin.willHandleBackgroundNotifications(notificationData);
    if (willHandleNotification == true) {
      _genuinSdkPlugin.handleBackgroundNotifications(notificationData);
    } else {
      // 您的通知处理
    }
  }

  // 当应用在前台收到推送消息时调用此方法
  FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
    if (kDebugMode) {
      print('Handling a foreground message: ${message.messageId}');
      print('Message data: ${message.data}');
      print('Message notification: ${message.notification?.title}');
      print('Message notification: ${message.notification?.body}');
    }

    final notificationData = {
      'title': message.notification?.title,
      'body': message.notification?.body,
      'data': message.data,
      'icon': 'mipmap/ic_notification'
      // 或者 'icon':'drawable/ic_notification'[如果图像放在drawable文件夹下]
    };
    var willHandleNotification = await _genuinSdkPlugin.willHandleForegroundNotifications(notificationData);
    if (willHandleNotification == true) {
      _genuinSdkPlugin.handleForegroundNotifications(notificationData);
    } else {
      // 您的通知处理
    }
  });

  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

  // 当用户点击通知时调用此方法[当应用在后台/已关闭时收到推送通知]
  FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
    final notificationData = {
      'title': message.notification?.title,
      'body': message.notification?.body,
      'data': message.data,
    };
    var willHandleNotification = await _genuinSdkPlugin.willHandleBackgroundNotifications(notificationData);
    if (willHandleNotification == true) {
      _genuinSdkPlugin.handleBackgroundNotifications(notificationData);
    } else {
      // 您的通知处理
    }
  });

  runApp(const MyApp());
}
  1. 在SDK中显式处理SSO登录

要自动登录到SDK,您需要在用户登录到您的应用时调用以下方法。

注意:如果您已经实现了嵌入SSO,则不需要调用以下方法。

import 'package:genuin_sdk/genuin_sdk.dart';

final _genuinSdkPlugin = GenuinSdk();
await _genuinSdkPlugin.ssoLogin("YOUR_SSO_TOKEN");
  1. 在SDK中处理SSO注销

每当用户从您的应用中注销时,请调用以下方法。

import 'package:genuin_sdk/genuin_sdk.dart';

final _genuinSdkPlugin = GenuinSdk();
await _genuinSdkPlugin.ssoLogout();

示例代码

import 'package:flutter/material.dart';
import 'package:genuin_sdk/genuin_carousel_embed_view.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  [@override](/user/override)
  void initState() {
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('插件示例应用'),
        ),
        body: Column(
          children: [
            SizedBox(
              height: 300,
              width: MediaQuery.of(context).size.width,
              child: const Carousel(
                embedId: "YOUR_EMBED_ID",
                uniqueId: "UNIQUE_ID",
                ssoToken: "YOUR_SSO_TOKEN",
                isShowProfileEnabled: false,
                isDirectDeepLinkEnabled: false,
              ),
            )
          ],
        ),
      ),
    );
  }
}

更多关于Flutter集成Genuin服务插件genuin_sdk的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter集成Genuin服务插件genuin_sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


要在Flutter项目中集成genuin_sdk插件以使用Genuin服务,你可以按照以下步骤进行操作:

1. 添加依赖

首先,在你的pubspec.yaml文件中添加genuin_sdk插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  genuin_sdk: ^1.0.0  # 请使用最新版本

然后运行flutter pub get来获取依赖。

2. 初始化Genuin SDK

在你的Flutter应用中,你需要初始化Genuin SDK。通常,你可以在main.dart中的main函数中或者在应用的启动逻辑中进行初始化。

import 'package:genuin_sdk/genuin_sdk.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // 初始化Genuin SDK
  await GenuinSdk.initialize(
    apiKey: 'YOUR_API_KEY',  // 替换为你的API Key
    environment: GenuinEnvironment.production, // 或 GenuinEnvironment.sandbox
  );

  runApp(MyApp());
}

3. 使用Genuin SDK

初始化后,你可以在应用的不同部分使用Genuin SDK提供的功能。以下是一些常见的用法示例:

3.1 验证设备

你可以使用Genuin SDK来验证设备的真实性:

import 'package:genuin_sdk/genuin_sdk.dart';

Future<void> verifyDevice() async {
  try {
    bool isGenuine = await GenuinSdk.verifyDevice();
    if (isGenuine) {
      print('设备是正版的');
    } else {
      print('设备可能是盗版的');
    }
  } catch (e) {
    print('验证失败: $e');
  }
}

3.2 获取设备信息

你可以获取设备的详细信息:

import 'package:genuin_sdk/genuin_sdk.dart';

Future<void> getDeviceInfo() async {
  try {
    Map<String, dynamic> deviceInfo = await GenuinSdk.getDeviceInfo();
    print('设备信息: $deviceInfo');
  } catch (e) {
    print('获取设备信息失败: $e');
  }
}

4. 处理回调

Genuin SDK可能会在某些情况下触发回调,例如设备状态变化。你可以注册回调来处理这些事件:

import 'package:genuin_sdk/genuin_sdk.dart';

void setupCallbacks() {
  GenuinSdk.onDeviceStatusChanged((status) {
    print('设备状态变化: $status');
  });
}

5. 配置Android和iOS

根据Genuin SDK的要求,你可能需要在Android和iOS项目中进行一些额外的配置。

Android

android/app/build.gradle文件中,确保你启用了multidex

android {
    defaultConfig {
        multiDexEnabled true
    }
}

iOS

ios/Runner/Info.plist文件中,添加必要的权限和配置:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>
回到顶部