diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 8bc077d..9387d93 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -12,9 +12,16 @@ assignees: ''
Before creating an issue, make sure to check our documentation
and other issues for possible fixes to your problem
* https://pub.dev/documentation/snapkit/latest/
- * https://github.com/TimmyRB/snapkit/wiki
+ * https://github.com/TimmyRB/snapkit/README.md
-->
+## Versions
+
+ - SnapKit:
+ - Snapchat:
+ - iOS:
+ - Android:
+
## Steps to Reproduce
diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml
index 6859606..bf06e4c 100644
--- a/.github/workflows/build-android.yml
+++ b/.github/workflows/build-android.yml
@@ -19,10 +19,10 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
- java-version: '12.x'
+ java-version: '17.x'
- uses: subosito/flutter-action@v1
with:
- flutter-version: '2.0.5'
+ flutter-version: '3.16.5'
- name: Get Dependancies
run: flutter pub get
diff --git a/.github/workflows/build-ios.yml b/.github/workflows/build-ios.yml
index 78b406f..84d9ea5 100644
--- a/.github/workflows/build-ios.yml
+++ b/.github/workflows/build-ios.yml
@@ -19,10 +19,10 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
- java-version: '12.x'
+ java-version: '17.x'
- uses: subosito/flutter-action@v1
with:
- flutter-version: '2.0.5'
+ flutter-version: '3.16.5'
- name: Get Dependancies
run: flutter pub get
diff --git a/.github/workflows/code-analysis.yml b/.github/workflows/code-analysis.yml
index f39f289..4472bce 100644
--- a/.github/workflows/code-analysis.yml
+++ b/.github/workflows/code-analysis.yml
@@ -19,10 +19,10 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
- java-version: '12.x'
+ java-version: '17.x'
- uses: subosito/flutter-action@v1
with:
- flutter-version: '2.0.5'
+ flutter-version: '3.16.5'
- name: Get Dependancies
run: flutter pub get
diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml
deleted file mode 100644
index f47eb81..0000000
--- a/.idea/libraries/Dart_SDK.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index e15c872..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/.idea/runConfigurations/example_lib_main_dart.xml b/.idea/runConfigurations/example_lib_main_dart.xml
deleted file mode 100644
index 5fd9159..0000000
--- a/.idea/runConfigurations/example_lib_main_dart.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
deleted file mode 100644
index b2558cb..0000000
--- a/.idea/workspace.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.metadata b/.metadata
index 3596a29..22257e4 100644
--- a/.metadata
+++ b/.metadata
@@ -4,7 +4,30 @@
# This file should be version controlled and should not be manually edited.
version:
- revision: 48c9d3e0e19e8fec84f1d316ce0559f26ca7277d
- channel: beta
+ revision: "78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9"
+ channel: "stable"
project_type: plugin
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ - platform: android
+ create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ - platform: ios
+ create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+ base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 34b7811..fdb762d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -44,4 +44,19 @@
* Fixed an issue where a user not sharing their Bitmoji would cause an exception
* Fixed Videos not working on Android Clients
* Fixed an issue where some Videos wouldn't work despite meeting Snapchat's Video requirements
-* Bug fixes & Code improvements
\ No newline at end of file
+* Bug fixes & Code improvements
+
+## 3.0.0
+
+* Restructured the project
+* Upgraded SnapSDK to 2.1.0 for Android
+* Upgraded SnapSDK to 2.5.0 for iOS
+* Split LoginKit & CreativeKit into their own classes
+* Classes now have static references to an Instance allow calls across pages without having to pass instances around
+* The current user is now saved on an instance of LoginKit allowing access across your entire app
+* Added OIDC to the current user's data
+* Added a caller for the access token
+* Added lots of error checking in platform code and more verbose errors
+* Fixed issue where videos wouldn't send on Android
+* Removed deprecated Verify Phone Number
+
diff --git a/README.md b/README.md
index 6443e0f..94b45e8 100644
--- a/README.md
+++ b/README.md
@@ -1,111 +1,337 @@
# Snapkit
[](https://pub.dev/packages/snapkit)
-[](https://github.com/TimmyRB/snapkit/actions/workflows/code-analysis.yml)
-[](https://github.com/TimmyRB/snapkit/actions/workflows/build-android.yml)
-[](https://github.com/TimmyRB/snapkit/actions/workflows/build-ios.yml)
+[](https://github.com/TimmyRB/snapkit/actions/workflows/code-analysis.yml)
+[](https://github.com/TimmyRB/snapkit/actions/workflows/build-android.yml)
+[](https://github.com/TimmyRB/snapkit/actions/workflows/build-ios.yml)
-A plugin that allows developers like you to integrate with Snapchat (using [SnapKit](https://kit.snapchat.com)) into your Flutter applications!
+A plugin that allows developers like you to integrate with Snapchat (using [Snapchat's Native SnapKit](https://kit.snapchat.com)) in your Flutter applications!
-## Getting Started
+Contents:
-Follow the [Wiki](https://github.com/TimmyRB/snapkit/wiki) for steps on how to get setup in an existing project or just copy the [example](example) project into a directory of your choosing and rename it.
+ - [What's New](#✨-whats-new)
+ - [Installation](#🛠️-installation)
+ - [Upgrading](#upgrading-from-older-versions)
+ - [iOS Setup](#-ios-setup)
+ - [Android Setup](#🤖-android-setup)
+ - [Usage](#✏️-usage)
+ - [LoginKit](#loginkit)
+ - [CreativeKit](#creativekit)
-## Usage
+## ✨ What's new
-### Create new Instance
-```dart
-Snapkit snapkit = new Snapkit();
+This flutter plugin has now been updated to 3.0.0 and contains breaking changes from any project using versions <= 2.0.0. This plugin now uses the following versions for Snapchat's native SDKs.
+
+```
+iOS: ~2.5.0
+Android: ~2.1.0
```
-### AuthState Stream
-```dart
-snapkit.onAuthStateChanged.listen((SnapchatUser? user) {
- // Do something with the returned SnapchatUser or null here
-});
+## 🛠️ Installation
+
+Add it to your project
+```
+flutter pub add snapkit
```
-### AuthState Class
+Import it
```dart
-class MyAppState extends State implements SnapchatAuthStateListener {
+import 'package:snapkit/snapkit.dart';
+```
- snapkit.addAuthStateListener(this);
+The following setup instructions assume you have created an app on the [Snapchat Developer Portal](https://devportal.snap.com/manage/) and have enabled 'Login Kit', 'Bitmoji Kit' & 'Creative Kit' in your app's settings. Make sure to setup a redirect URI in the 'Login Kit' settings and add your Snapchat username as a demo user in the general tab.
- @override
- void onLogin(SnapchatUser user) {
- // Do something with the returned SnapchatUser here
- }
+### Upgrading from older versions
- @override
- void onLogout() {
- // Do something on logout
- }
+On iOS the Installation is the same as before, however on Android you will need to modify and remove a few lines if you're upgrading from < 3.0.0.
+Firstly, remove this line from your `app/android/build.grade`
+
+```groovy
+maven {
+ url "https://storage.googleapis.com/snap-kit-build/maven"
}
```
-### Login
+Next, in your `app/android/app/build.grade`, remove these lines
+
+```groovy
+ implementation([
+ 'com.snapchat.kit.sdk:creative:1.10.0',
+ 'com.snapchat.kit.sdk:login:1.10.0',
+ 'com.snapchat.kit.sdk:bitmoji:1.10.0',
+ 'com.snapchat.kit.sdk:core:1.10.0'
+])
+```
+
+Finally, in your `app/android/app/src/main/AndroidManifest.xml`
+
+Change the following
+```xml
+com.snapchat.kit.sdk.clientId → com.snap.kit.clientId
+com.snapchat.kit.sdk.redirectUrl → com.snap.kit.redirectUrl
+com.snapchat.kit.sdk.scopes → com.snap.kit.scopes
+```
+
+And remove these lines
+```xml
+
+
+
+```
+
+### iOS Setup
+
+Add the following to your `Info.plist` in `app/ios/Runner/`. Make sure to replace `YOUR_CLIENT_ID_HERE`, `YOUR_REDIRECT_URL_HERE` & `YOUR_URL_SCHEME_HERE` with the correct information from your [Snapchat Developer Portal](https://devportal.snap.com/manage/)
+
+```plist
+SCSDKClientId
+YOUR_CLIENT_ID_HERE
+SCSDKRedirectUrl
+YOUR_REDIRECT_URL_HERE
+SCSDKScopes
+
+ https://auth.snapchat.com/oauth2/api/user.display_name
+ https://auth.snapchat.com/oauth2/api/user.bitmoji.avatar
+
+LSApplicationQueriesSchemes
+
+ snapchat
+ bitmoji-sdk
+ itms-apps
+
+CFBundleURLSchemes
+
+ YOUR_URL_SCHEME_HERE
+
+```
+
+Your redirect url should be in a similar format and must match one of the redirect URIs you should've made in the Login Kit settings on the [Snapchat Developer Portal](https://devportal.snap.com/manage/)
+```
+myapp://snapkit/oauth2
+```
+
+Your url scheme is the text that comes before `://` in your redirect url, so if you are using the redirect url above, your url scheme would be
+```
+myapp
+```
+
+Next in XCode, open `Runner.xcworkspace` from `app/ios/`, then in `Runner → Targets → Runner → Info` scroll to the bottom of the `Info` tab, expand `URL Types` and press the add + button. Set the identifer to be your application's bundle identifier e.g. `com.example.app` and set URL schemes to be the url scheme you determined above, e.g. `myapp`.
+
+Finally, add the following to your `AppDelegate.swift` file in `app/ios/Runner/` in order to be able to use the redirect url you just created
+
+```swift
+import UIKit
+import Flutter
+import SCSDKLoginKit // Add this import
+
+@UIApplicationMain
+@objc class AppDelegate: FlutterAppDelegate {
+ override func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+ ) -> Bool {
+ GeneratedPluginRegistrant.register(with: self)
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+
+ // Add this function
+ override func application(
+ _ app: UIApplication,
+ open url: URL,
+ options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
+ return SCSDKLoginClient.application(app, open: url, options: options)
+ }
+}
+```
+
+### 🤖 Android Setup
+
+Add the following to your `AndroidMainfest.xml` in `app/android/app/src/main` Make sure to replace `YOUR_CLIENT_ID_HERE`, `YOUR_SCHEME`, `YOUR_HOST` & `YOUR_PATH` with the correct information from your [Snapchat Developer Portal](https://devportal.snap.com/manage/)
+
+`YOUR_SCHEME://YOUR_HOST/YOUR_PATH` Is your redirect URL from the Developer Portal that you should've made when enabling LoginKit. You will need to split up these redirect url segements in the `SnapKitActivity` block.
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+...
+```
+
+Create a file named `arrays.xml` in `app/android/app/src/main/res/values` with the following content
+```xml
+
+
+
+ - https://auth.snapchat.com/oauth2/api/user.bitmoji.avatar
+ - https://auth.snapchat.com/oauth2/api/user.display_name
+ - https://auth.snapchat.com/oauth2/api/user.external_id
+
+
+```
+
+Create another file named `file_paths.xml` in `app/android/app/src/main/res/xml` with the following
+```xml
+
+
+
+
+```
+
+
+## ✏️ Usage
+
+Determine if Snapchat is installed on a user's device
```dart
-await snapkit.login();
+await SnapKit.I.isSnapchatInstalled() → bool
+```
+
+Check the version of the native SnapSDK running
+```dart
+await SnapKit.I.getSnapSDKVersion() → String
+```
-// or
+### LoginKit
-snapkit.login().then(user => {});
+This Kit is used for authenticating with the user's Snapchat account. Using this Kit allows you to get a user's External ID, OIDC, Display Name, Bitmoji URL & Access Token.
+
+Check if a user is already logged in
+```dart
+await LoginKit.I.isLoggedIn() → bool
```
-### Logout
+Start the login flow
```dart
-await snapkit.logout();
+await LoginKit.I.login()
+```
-// or
+Logging in automatically fetchs the user's data from Snapchat, however if you need to refresh it for whatever reason you can do so manually
+```dart
+await LoginKit.I.getCurrentUser()
+```
-snapkit.logout().then(() => {});
+Since only one user can be authenticated with Snapchat at a time on a device, the current user and their data is found here
+```dart
+LoginKit.I.currentUser → SnapchatUser
+```
+
+Retrieve the access token like this
+```dart
+await LoginKit.I.getAccessToken() → String?
```
-### Verify a Phone Number
-Returns a `bool` if Snapchat has verified the phone number, throws
-an error if there was a problem. Always returns `false` on Android
+Logout the user and unlink from the current session
```dart
-snapkit.verifyPhoneNumber('US', '1231234567')
- .then(isVerified {})
- .catchError((error, StackTrace stacktrace) {})
+await LoginKit.I.logout()
```
-## Share to Snapchat
+### CreativeKit
+
+This Kit is used for sharing photos, videos, stickers and more to Snapchat from inside your app. This Kit does **not** require the user be authenticated with LoginKit.
+
+#### Media Size and Length Restrictions:
+
+Shared media must be 300 MB or smaller.\
+Videos must be 60 seconds or shorter.\
+Videos that are longer than 10 seconds are split up into multiple Snaps of 10 seconds or less.
+
+#### Suggested Media Parameters:
+
+Aspect Ratio: 9:16\
+Preferred Image File Types: .jpg or .png\
+Preferred Video File Types: .mp4 or .mov\
+Dimensions: 1080px x 1920px\
+Video Bitrate: 1080p at 8mbps or 720p at 5mbps
+
+Create a Sticker
+```dart
+var sticker = CreativeKitSticker(
+ AssetImage('assets/image.png'),
+ size: StickerSize(32, 32),
+ offset: StickerOffset(0.5, 0.5),
+ rotation: StickerRotation(30),
+ );
+```
-### Share to LIVE
+Share to the Snapchat Camera
```dart
-snapkit.share(SnapchatMediaType.NONE,
- sticker: SnapchatSticker?,
- caption: String?,
- attachmentUrl: String?
-);
+CreativeKit.I.shareToCamera(
+ sticker: sticker,
+ caption: 'This is Awesome!',
+ link: Uri.parse('https://jacobbrasil.com/'),
+)
```
-### Share with Background Photo
+Share with a background Photo
```dart
-snapkit.share(SnapchatMediaType.PHOTO,
- image: ImageProvider,
- sticker: SnapchatSticker?,
- caption: String?,
- attachmentUrl: String?
-);
+CreativeKit.I.shareWithPhoto(
+ AssetImage('assets/image.png'),
+ sticker: sticker,
+ caption: 'This is Awesome!',
+ link: Uri.parse('https://jacobbrasil.com/'),
+)
```
-### Share with Background Video
-Currently unavailable on Android
+Share with a background Video that's available locally
```dart
-snapkit.share(SnapchatMediaType.VIDEO,
- videoUrl: String,
- sticker: SnapchatSticker?,
- caption: String?,
- attachmentUrl: String?
-);
+CreativeKit.I.shareWithVideo(
+ DefaultAssetBundle.of(context).load('assets/video.mp4'),
+ sticker: sticker,
+ caption: 'This is Awesome!',
+ link: Uri.parse('https://jacobbrasil.com/'),
+)
```
-### SnapchatSticker
+Share with a background Video that's available online
```dart
-new SnapchatSticker(
- image: ImageProvider
-);
+CreativeKit.I.shareWithRemoteVideo(
+ Uri.parse('https://link.to/video.mp4'),
+ sticker: sticker,
+ caption: 'This is Awesome!',
+ link: Uri.parse('https://jacobbrasil.com/'),
+)
```
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000..a5744c1
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: package:flutter_lints/flutter.yaml
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/android/.classpath b/android/.classpath
deleted file mode 100644
index 4a04201..0000000
--- a/android/.classpath
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/android/.gitignore b/android/.gitignore
index c6cbe56..161bdcd 100644
--- a/android/.gitignore
+++ b/android/.gitignore
@@ -6,3 +6,4 @@
.DS_Store
/build
/captures
+.cxx
diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs
deleted file mode 100644
index 4b1bb56..0000000
--- a/android/.settings/org.eclipse.buildship.core.prefs
+++ /dev/null
@@ -1,13 +0,0 @@
-arguments=
-auto.sync=false
-build.scans.enabled=false
-connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.8))
-connection.project.dir=../example/android
-eclipse.preferences.version=1
-gradle.user.home=
-java.home=/Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home
-jvm.arguments=
-offline.mode=false
-override.workspace.settings=true
-show.console.view=true
-show.executions.view=true
diff --git a/android/bin/.gitignore b/android/bin/.gitignore
new file mode 100644
index 0000000..161bdcd
--- /dev/null
+++ b/android/bin/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.cxx
diff --git a/android/.project b/android/bin/.project
similarity index 87%
rename from android/.project
rename to android/bin/.project
index a5e9298..39b047f 100644
--- a/android/.project
+++ b/android/bin/.project
@@ -22,12 +22,12 @@
- 1613022023091
+ 1706223300483
30
org.eclipse.core.resources.regexFilterMatcher
- node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+ node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
diff --git a/android/bin/build.gradle b/android/bin/build.gradle
new file mode 100644
index 0000000..ba25be6
--- /dev/null
+++ b/android/bin/build.gradle
@@ -0,0 +1,72 @@
+group 'com.jacobbrasil.snapkit'
+version '1.0-SNAPSHOT'
+
+buildscript {
+ ext.kotlin_version = '1.7.10'
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:7.3.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+
+android {
+ if (project.android.hasProperty("namespace")) {
+ namespace 'com.jacobbrasil.snapkit'
+ }
+
+ compileSdkVersion 33
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ test.java.srcDirs += 'src/test/kotlin'
+ }
+
+ defaultConfig {
+ minSdkVersion 19
+ }
+
+ dependencies {
+ testImplementation 'org.jetbrains.kotlin:kotlin-test'
+ testImplementation 'org.mockito:mockito-core:5.0.0'
+ implementation([
+ 'com.snap.loginkit:loginkit:2.0.0', // for Login Kit
+ 'com.snap.creativekit:creativekit:2.0.0', // for Creative Kit
+ ])
+ }
+
+ testOptions {
+ unitTests.all {
+ useJUnitPlatform()
+
+ testLogging {
+ events "passed", "skipped", "failed", "standardOut", "standardError"
+ outputs.upToDateWhen {false}
+ showStandardStreams = true
+ }
+ }
+ }
+}
diff --git a/android/bin/settings.gradle b/android/bin/settings.gradle
new file mode 100644
index 0000000..5f554cc
--- /dev/null
+++ b/android/bin/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'snapkit'
diff --git a/android/bin/src/main/AndroidManifest.xml b/android/bin/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e1bae7f
--- /dev/null
+++ b/android/bin/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/android/bin/src/main/kotlin/com/jacobbrasil/snapkit/SnapkitPlugin.kt b/android/bin/src/main/kotlin/com/jacobbrasil/snapkit/SnapkitPlugin.kt
new file mode 100644
index 0000000..cbc0e2b
--- /dev/null
+++ b/android/bin/src/main/kotlin/com/jacobbrasil/snapkit/SnapkitPlugin.kt
@@ -0,0 +1,35 @@
+package com.jacobbrasil.snapkit
+
+import androidx.annotation.NonNull
+
+import io.flutter.embedding.engine.plugins.FlutterPlugin
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import io.flutter.plugin.common.MethodChannel.MethodCallHandler
+import io.flutter.plugin.common.MethodChannel.Result
+
+/** SnapkitPlugin */
+class SnapkitPlugin: FlutterPlugin, MethodCallHandler {
+ /// The MethodChannel that will the communication between Flutter and native Android
+ ///
+ /// This local reference serves to register the plugin with the Flutter Engine and unregister it
+ /// when the Flutter Engine is detached from the Activity
+ private lateinit var channel : MethodChannel
+
+ override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
+ channel = MethodChannel(flutterPluginBinding.binaryMessenger, "snapkit")
+ channel.setMethodCallHandler(this)
+ }
+
+ override fun onMethodCall(call: MethodCall, result: Result) {
+ if (call.method == "getPlatformVersion") {
+ result.success("Android ${android.os.Build.VERSION.RELEASE}")
+ } else {
+ result.notImplemented()
+ }
+ }
+
+ override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
+ channel.setMethodCallHandler(null)
+ }
+}
diff --git a/android/bin/src/test/kotlin/com/jacobbrasil/snapkit/SnapkitPluginTest.kt b/android/bin/src/test/kotlin/com/jacobbrasil/snapkit/SnapkitPluginTest.kt
new file mode 100644
index 0000000..d1bcbe8
--- /dev/null
+++ b/android/bin/src/test/kotlin/com/jacobbrasil/snapkit/SnapkitPluginTest.kt
@@ -0,0 +1,27 @@
+package com.jacobbrasil.snapkit
+
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import kotlin.test.Test
+import org.mockito.Mockito
+
+/*
+ * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation.
+ *
+ * Once you have built the plugin's example app, you can run these tests from the command
+ * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
+ * you can run them directly from IDEs that support JUnit such as Android Studio.
+ */
+
+internal class SnapkitPluginTest {
+ @Test
+ fun onMethodCall_getPlatformVersion_returnsExpectedValue() {
+ val plugin = SnapkitPlugin()
+
+ val call = MethodCall("getPlatformVersion", null)
+ val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java)
+ plugin.onMethodCall(call, mockResult)
+
+ Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE)
+ }
+}
diff --git a/android/build.gradle b/android/build.gradle
index c94748f..9520b07 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,42 +1,72 @@
group 'com.jacobbrasil.snapkit'
-version '1.0'
+version '1.0-SNAPSHOT'
buildscript {
+ ext.kotlin_version = '1.7.10'
repositories {
google()
- jcenter()
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.1.0'
+ classpath 'com.android.tools.build:gradle:7.3.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
-rootProject.allprojects {
+allprojects {
repositories {
google()
- jcenter()
- maven {
- url "https://storage.googleapis.com/snap-kit-build/maven"
- }
+ mavenCentral()
}
}
apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
android {
- compileSdkVersion 30
+ if (project.android.hasProperty("namespace")) {
+ namespace 'com.jacobbrasil.snapkit'
+ }
+
+ compileSdk 33
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ test.java.srcDirs += 'src/test/kotlin'
+ }
defaultConfig {
- minSdkVersion 19
+ minSdkVersion 33
}
-}
-dependencies {
- implementation([
- 'com.snapchat.kit.sdk:creative:1.10.0',
- 'com.snapchat.kit.sdk:login:1.10.0',
- 'com.snapchat.kit.sdk:bitmoji:1.10.0',
- 'com.snapchat.kit.sdk:core:1.10.0'
- ])
+ dependencies {
+ testImplementation 'org.jetbrains.kotlin:kotlin-test'
+ testImplementation 'org.mockito:mockito-core:5.0.0'
+ implementation([
+ 'com.snap.loginkit:loginkit:2.1.0', // for Login Kit
+ 'com.snap.creativekit:creativekit:2.1.0', // for Creative Kit
+ ])
+ }
+
+ testOptions {
+ unitTests.all {
+ useJUnitPlatform()
+
+ testLogging {
+ events "passed", "skipped", "failed", "standardOut", "standardError"
+ outputs.upToDateWhen {false}
+ showStandardStreams = true
+ }
+ }
+ }
}
diff --git a/android/gradle.properties b/android/gradle.properties
deleted file mode 100644
index 94adc3a..0000000
--- a/android/gradle.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-org.gradle.jvmargs=-Xmx1536M
-android.useAndroidX=true
-android.enableJetifier=true
diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7454180
Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 3c9d085..0e9a610 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index e1bae7f..2be0412 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -1,3 +1,6 @@
+
+
+
diff --git a/android/src/main/java/com/jacobbrasil/snapkit/SnapkitPlugin.java b/android/src/main/java/com/jacobbrasil/snapkit/SnapkitPlugin.java
deleted file mode 100644
index 7159187..0000000
--- a/android/src/main/java/com/jacobbrasil/snapkit/SnapkitPlugin.java
+++ /dev/null
@@ -1,231 +0,0 @@
-package com.jacobbrasil.snapkit;
-
-import android.app.Activity;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.snapchat.kit.sdk.SnapCreative;
-import com.snapchat.kit.sdk.SnapLogin;
-import com.snapchat.kit.sdk.core.controller.LoginStateController.OnLoginStateChangedListener;
-import com.snapchat.kit.sdk.creative.api.SnapCreativeKitApi;
-import com.snapchat.kit.sdk.creative.exceptions.SnapMediaSizeException;
-import com.snapchat.kit.sdk.creative.exceptions.SnapStickerSizeException;
-import com.snapchat.kit.sdk.creative.exceptions.SnapVideoLengthException;
-import com.snapchat.kit.sdk.creative.media.SnapMediaFactory;
-import com.snapchat.kit.sdk.creative.media.SnapPhotoFile;
-import com.snapchat.kit.sdk.creative.media.SnapSticker;
-import com.snapchat.kit.sdk.creative.media.SnapVideoFile;
-import com.snapchat.kit.sdk.creative.models.SnapContent;
-import com.snapchat.kit.sdk.creative.models.SnapLiveCameraContent;
-import com.snapchat.kit.sdk.creative.models.SnapPhotoContent;
-import com.snapchat.kit.sdk.creative.models.SnapVideoContent;
-import com.snapchat.kit.sdk.login.models.MeData;
-import com.snapchat.kit.sdk.login.models.UserDataResponse;
-import com.snapchat.kit.sdk.login.networking.FetchUserDataCallback;
-import com.snapchat.kit.sdk.util.SnapUtils;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import io.flutter.embedding.engine.plugins.FlutterPlugin;
-import io.flutter.embedding.engine.plugins.activity.ActivityAware;
-import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
-import io.flutter.plugin.common.MethodCall;
-import io.flutter.plugin.common.MethodChannel;
-import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
-import io.flutter.plugin.common.MethodChannel.Result;
-
-/**
- * SnapkitPlugin
- */
-public class SnapkitPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware, OnLoginStateChangedListener {
- /// The MethodChannel that will the communication between Flutter and native Android
- ///
- /// This local reference serves to register the plugin with the Flutter Engine and unregister it
- /// when the Flutter Engine is detached from the Activity
- private MethodChannel channel;
- private Activity _activity;
- private MethodChannel.Result _result;
- private SnapCreativeKitApi creativeKitApi;
- private SnapMediaFactory mediaFactory;
-
- @Override
- public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
- channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "snapkit");
- channel.setMethodCallHandler(this);
- }
-
- @Override
- public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) {
- switch (call.method) {
- case "callLogin":
- SnapLogin.getLoginStateController(_activity).addOnLoginStateChangedListener(this);
- SnapLogin.getAuthTokenManager(_activity).startTokenGrant();
- _result = result;
- break;
- case "getUser":
- String query = "{me{externalId, displayName, bitmoji{selfie}}}";
- SnapLogin.fetchUserData(_activity, query, null, new FetchUserDataCallback() {
- @Override
- public void onSuccess(@Nullable UserDataResponse userDataResponse) {
- if (userDataResponse == null || userDataResponse.getData() == null) {
- return;
- }
-
- MeData meData = userDataResponse.getData().getMe();
- if (meData == null) {
- result.error("GetUserError", "Returned MeData was null", null);
- return;
- }
-
- List res = new ArrayList();
- res.add(meData.getExternalId());
- res.add(meData.getDisplayName());
- res.add(meData.getBitmojiData().getSelfie());
-
- result.success(res);
- }
-
- @Override
- public void onFailure(boolean isNetworkError, int statusCode) {
- if (isNetworkError) {
- result.error("NetworkGetUserError", "Network Error", statusCode);
- } else {
- result.error("UnknownGetUserError", "Unknown Error", statusCode);
- }
- }
- });
- break;
- case "sendMedia":
- if (creativeKitApi == null) creativeKitApi = SnapCreative.getApi(_activity);
- if (mediaFactory == null) mediaFactory = SnapCreative.getMediaFactory(_activity);
-
- SnapContent content;
- switch ((String)call.argument("mediaType")) {
- case "PHOTO":
- try {
- SnapPhotoFile photoFile = mediaFactory.getSnapPhotoFromFile(new File((String) call.argument("imagePath")));
- content = new SnapPhotoContent(photoFile);
- } catch (SnapMediaSizeException e) {
- result.error("SendMediaError", "Could not create SnapPhotoFile", e);
- return;
- } catch (NullPointerException e) {
- result.error("SendMediaError", "Could not find Image file", e);
- return;
- }
-
- break;
- case "VIDEO":
- try {
- SnapVideoFile videoFile = mediaFactory.getSnapVideoFromFile(new File((String) call.argument("videoPath")));
- content = new SnapVideoContent(videoFile);
- } catch (SnapMediaSizeException | SnapVideoLengthException e) {
- result.error("SendMediaError", "Could not create SnapVideoFile", e);
- return;
- } catch (NullPointerException e) {
- result.error("SendMediaError", "Could not find Video file", e);
- return;
- }
-
- break;
- default:
- content = new SnapLiveCameraContent();
- break;
- }
-
- content.setCaptionText((String)call.argument("caption"));
- content.setAttachmentUrl((String)call.argument("attachmentUrl"));
-
- if (call.argument("sticker") != null) {
- Map stickerMap = (Map) call.argument("sticker");
- SnapSticker sticker = null;
- try {
- sticker = mediaFactory.getSnapStickerFromFile(new File((String) stickerMap.get("imagePath")));
- } catch (SnapStickerSizeException e) {
- result.error("SendMediaError", "Could not create SnapSticker", e);
- return;
- } catch (NullPointerException e) {
- result.error("SendMediaError", "Could not find Sticker file", e);
- return;
- }
-
- if (sticker != null) {
- sticker.setWidthDp(Float.parseFloat(stickerMap.get("width").toString()));
- sticker.setHeightDp(Float.parseFloat(stickerMap.get("height").toString()));
-
- sticker.setPosX(Float.parseFloat(stickerMap.get("offsetX").toString()));
- sticker.setPosY(Float.parseFloat(stickerMap.get("offsetY").toString()));
-
- sticker.setRotationDegreesClockwise(Float.parseFloat(stickerMap.get("rotation").toString()));
-
- content.setSnapSticker(sticker);
- }
- }
-
- creativeKitApi.send(content);
- break;
- case "verifyNumber":
- List res = new ArrayList();
- res.add("");
- res.add("");
- result.success(res);
- break;
- case "callLogout":
- SnapLogin.getAuthTokenManager(_activity).clearToken();
- _result = result;
- break;
- case "isInstalled":
- result.success(SnapUtils.isSnapchatInstalled(_activity.getPackageManager(), "com.snapchat.android"));
- break;
- case "getPlatformVersion":
- result.success("Android " + android.os.Build.VERSION.RELEASE);
- break;
- default:
- result.notImplemented();
- break;
- }
- }
-
- @Override
- public void onLoginSucceeded() {
- _result.success("Login Success");
- }
-
- @Override
- public void onLoginFailed() {
- _result.error("LoginError", "Error Logging In", null);
- }
-
- @Override
- public void onLogout() {
- _result.success("Logout Success");
- }
-
- @Override
- public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
- channel.setMethodCallHandler(null);
- }
-
- @Override
- public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
- _activity = binding.getActivity();
- }
-
- @Override
- public void onDetachedFromActivityForConfigChanges() {
-
- }
-
- @Override
- public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
-
- }
-
- @Override
- public void onDetachedFromActivity() {
-
- }
-}
diff --git a/android/src/main/kotlin/com/jacobbrasil/snapkit/SnapkitPlugin.kt b/android/src/main/kotlin/com/jacobbrasil/snapkit/SnapkitPlugin.kt
new file mode 100644
index 0000000..07158d5
--- /dev/null
+++ b/android/src/main/kotlin/com/jacobbrasil/snapkit/SnapkitPlugin.kt
@@ -0,0 +1,316 @@
+package com.jacobbrasil.snapkit
+
+import android.app.Activity
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.PackageInfoFlags
+import android.util.Log
+import com.snap.creativekit.SnapCreative
+import com.snap.creativekit.api.SnapCreativeKitApi
+import com.snap.creativekit.api.SnapCreativeKitCompletionCallback
+import com.snap.creativekit.api.SnapCreativeKitSendError
+import com.snap.creativekit.exceptions.SnapMediaSizeException
+import com.snap.creativekit.exceptions.SnapStickerSizeException
+import com.snap.creativekit.exceptions.SnapVideoLengthException
+import com.snap.creativekit.media.SnapMediaFactory
+import com.snap.creativekit.models.SnapContent
+import com.snap.creativekit.models.SnapLiveCameraContent
+import com.snap.creativekit.models.SnapPhotoContent
+import com.snap.creativekit.models.SnapVideoContent
+import com.snap.loginkit.AccessTokenResultCallback
+import com.snap.loginkit.BitmojiQuery
+import com.snap.loginkit.LoginResultCallback
+import com.snap.loginkit.SnapLoginProvider
+import com.snap.loginkit.UserDataQuery
+import com.snap.loginkit.UserDataResultCallback
+import com.snap.loginkit.exceptions.AccessTokenException
+import com.snap.loginkit.exceptions.LoginException
+import com.snap.loginkit.exceptions.UserDataException
+import com.snap.loginkit.models.UserDataResult
+import io.flutter.embedding.engine.plugins.FlutterPlugin
+import io.flutter.embedding.engine.plugins.activity.ActivityAware
+import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import io.flutter.plugin.common.MethodChannel.MethodCallHandler
+import io.flutter.plugin.common.MethodChannel.Result
+import java.io.File
+import java.util.Objects
+
+
+/** SnapkitPlugin */
+class SnapkitPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
+ /// The MethodChannel that will the communication between Flutter and native Android
+ ///
+ /// This local reference serves to register the plugin with the Flutter Engine and unregister it
+ /// when the Flutter Engine is detached from the Activity
+ private lateinit var channel : MethodChannel
+
+ private var _activity : Activity? = null
+
+ private var _snapApi : SnapCreativeKitApi? = null
+ private var _snapMediaFactory : SnapMediaFactory? = null
+
+ private fun requireActivity(): Activity {
+ return Objects.requireNonNull(_activity, "Snapkit plugin is not attached to an activity.")
+ }
+
+ private fun getSnapApi(): SnapCreativeKitApi {
+ if (_snapApi == null) {
+ _snapApi = SnapCreative.getApi(requireActivity())
+ }
+
+ return _snapApi!!
+ }
+
+ private fun getSnapMediaFactory(): SnapMediaFactory {
+ if (_snapMediaFactory == null) {
+ _snapMediaFactory = SnapCreative.getMediaFactory(requireActivity())
+ }
+
+ return _snapMediaFactory!!
+ }
+
+ override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
+ channel = MethodChannel(flutterPluginBinding.binaryMessenger, "snapkit")
+ channel.setMethodCallHandler(this)
+ }
+
+ override fun onMethodCall(call: MethodCall, result: Result) {
+ when (call.method) {
+ "sdkVersion" -> {
+ result.success(SnapLoginProvider.getVersion())
+ }
+ "isSnapchatInstalled" -> {
+ try {
+ val pm: PackageManager = requireActivity().packageManager
+ pm.getPackageInfo("com.snapchat.android", PackageInfoFlags.of(0))
+ result.success(true)
+ } catch (e: PackageManager.NameNotFoundException) {
+ result.success(false)
+ }
+ }
+ "isLoggedIn" -> {
+ result.success(SnapLoginProvider.get(requireActivity()).isUserLoggedIn)
+ }
+ "login" -> {
+ Log.d("SNAPKIT", "Pre-Login Flow: " + requireActivity())
+ SnapLoginProvider.get(requireActivity()).startTokenGrant(object: LoginResultCallback {
+ override fun onStart() {
+ Log.d("SNAPKIT", "Login Flow Started")
+ }
+
+ override fun onSuccess(accessToken: String) {
+ result.success("Login Success")
+ }
+
+ override fun onFailure(exception: LoginException) {
+ result.error("LoginError", exception.localizedMessage, null)
+ }
+ })
+ }
+ "getCurrentUser" -> {
+ val bitmojiQuery = BitmojiQuery.newBuilder().withAvatarId().withTwoDAvatarUrl().build()
+ val userDataQuery = UserDataQuery.newBuilder().withExternalId().withIdToken().withDisplayName().withBitmoji(bitmojiQuery).build()
+
+ SnapLoginProvider.get(requireActivity()).fetchUserData(userDataQuery, object: UserDataResultCallback {
+ override fun onSuccess(userDataResult: UserDataResult) {
+ if (userDataResult.data?.meData == null) {
+ result.error("GetUserError", "User data was null", null)
+ return
+ }
+
+ val meData = userDataResult.data!!.meData!!
+ val map: HashMap = HashMap()
+ map["externalId"] = meData.externalId
+ map["openIdToken"] = meData.idToken
+ map["displayName"] = meData.displayName
+ map["bitmoji2DAvatarUrl"] = meData.bitmojiData?.twoDAvatarUrl
+ map["bitmojiAvatarId"] = meData.bitmojiData?.avatarId
+ map["errors"] = null
+
+ result.success(map)
+ }
+
+ override fun onFailure(exception: UserDataException) {
+ result.error("GetUserError", exception.localizedMessage, exception)
+ }
+ })
+ }
+ "getAccessToken" -> {
+ SnapLoginProvider.get(requireActivity()).fetchAccessToken(object: AccessTokenResultCallback {
+ override fun onSuccess(token: String) {
+ result.success(token)
+ }
+
+ override fun onFailure(e: AccessTokenException) {
+ result.error("GetAccessTokenError", e.localizedMessage, e)
+ }
+
+ })
+ }
+ "logout" -> {
+ SnapLoginProvider.get(requireActivity()).clearToken()
+ result.success("Logout Success")
+ }
+ "shareToCamera" -> {
+ if (call.arguments !is Map<*, *>) {
+ return
+ }
+
+ val args = call.arguments as Map<*, *>
+
+ try {
+ val content = handleCommonShare(args, SnapLiveCameraContent())
+
+ getSnapApi().sendWithCompletionHandler(content, object: SnapCreativeKitCompletionCallback {
+ override fun onSendSuccess() {
+ result.success("ShareToCamera Success")
+ }
+
+ override fun onSendFailed(e: SnapCreativeKitSendError?) {
+ result.error("ShareToCameraError", e?.name, e)
+ }
+ })
+ } catch (e: SnapStickerSizeException) {
+ result.error("ShareToCameraError", e.localizedMessage, e)
+ } catch (e: SnapKitException) {
+ result.error("ShareToCameraError", e.localizedMessage, "Error caused by handleCommonShare")
+ }
+ }
+ "shareWithPhoto" -> {
+ if (call.arguments !is Map<*, *>) {
+ return
+ }
+
+ val args = call.arguments as Map<*, *>
+
+ try {
+ val photo = File(args["photoPath"].toString())
+
+ if (!photo.exists()) {
+ result.error("ShareWithPhotoError","Photo could not be found in filesystem", null)
+ }
+
+ val content = handleCommonShare(args, SnapPhotoContent(getSnapMediaFactory().getSnapPhotoFromFile(photo)))
+
+ getSnapApi().sendWithCompletionHandler(content, object: SnapCreativeKitCompletionCallback {
+ override fun onSendSuccess() {
+ result.success("ShareWithPhoto Success")
+ }
+
+ override fun onSendFailed(e: SnapCreativeKitSendError?) {
+ result.error("ShareWithPhotoError", e?.name, e)
+ }
+ })
+ } catch (e: SnapMediaSizeException) {
+ result.error("ShareWithPhotoError", e.localizedMessage, e)
+ } catch (e: SnapStickerSizeException) {
+ result.error("ShareWithPhotoError", e.localizedMessage, e)
+ } catch (e: SnapKitException) {
+ result.error("ShareWithPhotoError", e.localizedMessage, "Error caused by handleCommonShare")
+ }
+ }
+ "shareWithVideo" -> {
+ if (call.arguments !is Map<*, *>) {
+ return
+ }
+
+ val args = call.arguments as Map<*, *>
+
+ try {
+ val video = File(args["videoPath"].toString())
+
+ if (!video.exists()) {
+ result.error("ShareWithVideoError","Video could not be found in filesystem", null)
+ }
+
+ val content = handleCommonShare(args, SnapVideoContent(getSnapMediaFactory().getSnapVideoFromFile(video)))
+
+ getSnapApi().sendWithCompletionHandler(content, object: SnapCreativeKitCompletionCallback {
+ override fun onSendSuccess() {
+ result.success("ShareWithVideo Success")
+ }
+
+ override fun onSendFailed(e: SnapCreativeKitSendError?) {
+ result.error("ShareWithVideoError", e?.name, e)
+ }
+ })
+ } catch (e: SnapMediaSizeException) {
+ result.error("ShareWithVideoError", e.localizedMessage, e)
+ } catch (e: SnapVideoLengthException) {
+ result.error("ShareWithVideoError", e.localizedMessage, e)
+ } catch (e: SnapStickerSizeException) {
+ result.error("ShareWithVideoError", e.localizedMessage, e)
+ } catch (e: SnapKitException) {
+ result.error("ShareWithVideoError", e.localizedMessage, "Error caused by handleCommonShare")
+ }
+ }
+ else -> {
+ result.notImplemented()
+ }
+ }
+ }
+
+ private fun handleCommonShare(args: Map<*, *>, content: SnapContent): SnapContent {
+ content.captionText = args["caption"].toString()
+ content.attachmentUrl = args["link"].toString()
+
+ if (args["sticker"] is Map<*, *>) {
+ val sticker = args["sticker"] as Map<*, *>
+
+ val image = File(sticker["imagePath"].toString())
+
+ if (!image.exists()) {
+ throw SnapKitException("Image could not be found in filesystem")
+ }
+
+ try {
+ val snapSticker = getSnapMediaFactory().getSnapStickerFromFile(image)
+
+ if (sticker["size"] is Map<*, *>) {
+ val size = sticker["size"] as Map<*, *>
+ snapSticker.setWidthDp((size["width"] as Double).toFloat())
+ snapSticker.setHeightDp((size["height"] as Double).toFloat())
+ } else {
+ snapSticker.setWidthDp(64f)
+ snapSticker.setHeightDp(64f)
+ }
+
+ if (sticker["offset"] is Map<*, *>) {
+ val offset = sticker["offset"] as Map<*, *>
+ snapSticker.setPosX((offset["x"] as Double).toFloat())
+ snapSticker.setPosY((offset["y"] as Double).toFloat())
+ }
+
+ if (sticker["rotation"] is Map<*, *>) {
+ val rotation = sticker["rotation"] as Map<*, *>
+ snapSticker.setRotationDegreesClockwise((rotation["angle"] as Double).toFloat())
+ }
+
+ content.snapSticker = snapSticker
+ } catch (e: SnapStickerSizeException) {
+ throw e
+ }
+ }
+
+ return content
+ }
+
+ override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
+ channel.setMethodCallHandler(null)
+ }
+
+ override fun onAttachedToActivity(binding: ActivityPluginBinding) {
+ _activity = binding.activity
+ }
+
+ override fun onDetachedFromActivity() {
+ _activity = null
+ }
+
+ override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { }
+
+ override fun onDetachedFromActivityForConfigChanges() { }
+}
+
+class SnapKitException(message: String): Exception(message)
diff --git a/android/src/test/kotlin/com/jacobbrasil/snapkit/SnapkitPluginTest.kt b/android/src/test/kotlin/com/jacobbrasil/snapkit/SnapkitPluginTest.kt
new file mode 100644
index 0000000..d1bcbe8
--- /dev/null
+++ b/android/src/test/kotlin/com/jacobbrasil/snapkit/SnapkitPluginTest.kt
@@ -0,0 +1,27 @@
+package com.jacobbrasil.snapkit
+
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import kotlin.test.Test
+import org.mockito.Mockito
+
+/*
+ * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation.
+ *
+ * Once you have built the plugin's example app, you can run these tests from the command
+ * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
+ * you can run them directly from IDEs that support JUnit such as Android Studio.
+ */
+
+internal class SnapkitPluginTest {
+ @Test
+ fun onMethodCall_getPlatformVersion_returnsExpectedValue() {
+ val plugin = SnapkitPlugin()
+
+ val call = MethodCall("getPlatformVersion", null)
+ val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java)
+ plugin.onMethodCall(call, mockResult)
+
+ Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE)
+ }
+}
diff --git a/example/.gitignore b/example/.gitignore
index 0fa6b67..29a3a50 100644
--- a/example/.gitignore
+++ b/example/.gitignore
@@ -8,6 +8,7 @@
.buildlog/
.history
.svn/
+migrate_working_dir/
# IntelliJ related
*.iml
@@ -26,14 +27,10 @@
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
-.packages
.pub-cache/
.pub/
/build/
-# Web related
-lib/generated_plugin_registrant.dart
-
# Symbolication related
app.*.symbols
diff --git a/example/.metadata b/example/.metadata
index 9f8c408..25d90ec 100644
--- a/example/.metadata
+++ b/example/.metadata
@@ -1,10 +1,30 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
-# This file should be version controlled and should not be manually edited.
+# This file should be version controlled.
version:
- revision: 48c9d3e0e19e8fec84f1d316ce0559f26ca7277d
- channel: beta
+ revision: 796c8ef79279f9c774545b3771238c3098dbefab
+ channel: stable
project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
+ base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
+ - platform: android
+ create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
+ base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/example/README.md b/example/README.md
index 35fd043..eea7e0a 100644
--- a/example/README.md
+++ b/example/README.md
@@ -8,9 +8,9 @@ This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
-- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
-- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
+- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
+- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
-For help getting started with Flutter, view our
-[online documentation](https://flutter.dev/docs), which offers tutorials,
+For help getting started with Flutter development, view the
+[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml
new file mode 100644
index 0000000..0d29021
--- /dev/null
+++ b/example/analysis_options.yaml
@@ -0,0 +1,28 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at https://dart.dev/lints.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/example/android/.gitignore b/example/android/.gitignore
index 0a741cb..6f56801 100644
--- a/example/android/.gitignore
+++ b/example/android/.gitignore
@@ -9,3 +9,5 @@ GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
+**/*.keystore
+**/*.jks
diff --git a/example/android/.project b/example/android/.project
deleted file mode 100644
index 2c241ce..0000000
--- a/example/android/.project
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
- android
- Project android created by Buildship.
-
-
-
-
- org.eclipse.buildship.core.gradleprojectbuilder
-
-
-
-
-
- org.eclipse.buildship.core.gradleprojectnature
-
-
-
- 1613022023065
-
- 30
-
- org.eclipse.core.resources.regexFilterMatcher
- node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
-
-
-
-
diff --git a/example/android/.settings/org.eclipse.buildship.core.prefs b/example/android/.settings/org.eclipse.buildship.core.prefs
deleted file mode 100644
index 9bb9226..0000000
--- a/example/android/.settings/org.eclipse.buildship.core.prefs
+++ /dev/null
@@ -1,13 +0,0 @@
-arguments=
-auto.sync=false
-build.scans.enabled=false
-connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
-connection.project.dir=
-eclipse.preferences.version=1
-gradle.user.home=
-java.home=/Library/Java/JavaVirtualMachines/jdk-11.0.12.jdk/Contents/Home
-jvm.arguments=
-offline.mode=false
-override.workspace.settings=true
-show.console.view=true
-show.executions.view=true
diff --git a/example/android/app/.classpath b/example/android/app/.classpath
deleted file mode 100644
index 4a04201..0000000
--- a/example/android/app/.classpath
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/example/android/app/.project b/example/android/app/.project
deleted file mode 100644
index 86579a0..0000000
--- a/example/android/app/.project
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
- app
- Project app created by Buildship.
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- org.eclipse.buildship.core.gradleprojectbuilder
-
-
-
-
-
- org.eclipse.jdt.core.javanature
- org.eclipse.buildship.core.gradleprojectnature
-
-
-
- 1613022023076
-
- 30
-
- org.eclipse.core.resources.regexFilterMatcher
- node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
-
-
-
-
diff --git a/example/android/app/.settings/org.eclipse.buildship.core.prefs b/example/android/app/.settings/org.eclipse.buildship.core.prefs
deleted file mode 100644
index b1886ad..0000000
--- a/example/android/app/.settings/org.eclipse.buildship.core.prefs
+++ /dev/null
@@ -1,2 +0,0 @@
-connection.project.dir=..
-eclipse.preferences.version=1
diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle
index 0080986..28d0f61 100644
--- a/example/android/app/build.gradle
+++ b/example/android/app/build.gradle
@@ -1,3 +1,9 @@
+plugins {
+ id "com.android.application"
+ id "kotlin-android"
+ id "dev.flutter.flutter-gradle-plugin"
+}
+
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
@@ -6,11 +12,6 @@ if (localPropertiesFile.exists()) {
}
}
-def flutterRoot = localProperties.getProperty('flutter.sdk')
-if (flutterRoot == null) {
- throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
-}
-
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
@@ -21,22 +22,31 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
-apply plugin: 'com.android.application'
-apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
-
android {
- compileSdkVersion 30
+ namespace "com.jacobbrasil.snapkit_example"
+ compileSdkVersion flutter.compileSdkVersion
+ ndkVersion flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ }
defaultConfig {
- // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.jacobbrasil.snapkit_example"
- minSdkVersion 19
- targetSdkVersion 30
+ // Snap Kit requires SDK version 19 or later, but `flutter.minSdkVersion` currently is 16.
+ minSdkVersion 33
+ targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
- ndk {
- abiFilters 'armeabi-v7a', 'arm64-v8a'
- }
}
buildTypes {
@@ -46,15 +56,6 @@ android {
signingConfig signingConfigs.debug
}
}
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- dependenciesInfo {
- includeInBundle true
- includeInApk true
- }
- buildToolsVersion '29.0.2'
}
flutter {
@@ -62,10 +63,5 @@ flutter {
}
dependencies {
- implementation([
- 'com.snapchat.kit.sdk:creative:1.10.0',
- 'com.snapchat.kit.sdk:login:1.10.0',
- 'com.snapchat.kit.sdk:bitmoji:1.10.0',
- 'com.snapchat.kit.sdk:core:1.10.0'
- ])
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml
index f562f73..399f698 100644
--- a/example/android/app/src/debug/AndroidManifest.xml
+++ b/example/android/app/src/debug/AndroidManifest.xml
@@ -1,6 +1,6 @@
-
-
diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml
index 85fb440..e7620c5 100644
--- a/example/android/app/src/main/AndroidManifest.xml
+++ b/example/android/app/src/main/AndroidManifest.xml
@@ -1,51 +1,54 @@
-
-
+
+
+
-
-
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
+
-
-
-
-
+
+
+
-
-
@@ -80,9 +74,4 @@
android:value="2" />
-
-
-
-
-
diff --git a/example/android/app/src/main/java/com/jacobbrasil/snapkit_example/MainActivity.java b/example/android/app/src/main/java/com/jacobbrasil/snapkit_example/MainActivity.java
deleted file mode 100644
index 588615a..0000000
--- a/example/android/app/src/main/java/com/jacobbrasil/snapkit_example/MainActivity.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.jacobbrasil.snapkit_example;
-
-import io.flutter.embedding.android.FlutterActivity;
-
-public class MainActivity extends FlutterActivity {
-}
diff --git a/example/android/app/src/main/kotlin/com/jacobbrasil/snapkit_example/MainActivity.kt b/example/android/app/src/main/kotlin/com/jacobbrasil/snapkit_example/MainActivity.kt
new file mode 100644
index 0000000..e651ba9
--- /dev/null
+++ b/example/android/app/src/main/kotlin/com/jacobbrasil/snapkit_example/MainActivity.kt
@@ -0,0 +1,6 @@
+package com.jacobbrasil.snapkit_example
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity() {
+}
diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml
index 449a9f9..06952be 100644
--- a/example/android/app/src/main/res/values-night/styles.xml
+++ b/example/android/app/src/main/res/values-night/styles.xml
@@ -3,14 +3,14 @@