├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── android ├── .gitignore ├── build.gradle ├── gradle.properties ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ └── com │ └── kf │ └── flutter_vk_sdk │ ├── FlutterVKApiDelegate.kt │ ├── FlutterVKResultDelegate.kt │ └── FlutterVKSdkPlugin.kt ├── example ├── .gitignore ├── .metadata ├── README.md ├── android │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── kf │ │ │ │ │ └── flutter_vk_sdk_example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ └── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── ios │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h ├── lib │ └── main.dart ├── pubspec.lock ├── pubspec.yaml └── test │ └── widget_test.dart ├── flutter_vk_sdk.iml ├── ios ├── .gitignore ├── Assets │ └── .gitkeep ├── Classes │ ├── FlutterVKSdkPlugin.h │ ├── FlutterVKSdkPlugin.m │ └── SwiftFlutterVKSdkPlugin.swift └── flutter_vk_sdk.podspec ├── lib ├── flutter_vk_sdk.dart ├── models │ ├── attachment.dart │ └── vk_access_token.dart ├── ui │ ├── vk_share_page.dart │ └── vk_theme.dart ├── utils │ └── share_utils.dart ├── vk_api │ ├── photos.dart │ ├── video.dart │ ├── vk_api.dart │ └── wall.dart ├── vk_method_call.dart ├── vk_response_parser.dart └── vk_scope.dart ├── pubspec.lock ├── pubspec.yaml └── test └── flutter_vk_sdk_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | 9 | .idea/ 10 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 8 | channel: stable 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.1.0 2 | 3 | * kotlin update to 1.3.50 4 | * gradle update to 3.5.0 5 | 6 | ## 0.0.1 7 | 8 | * TODO: Describe initial release. 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | TODO: Add your license here. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_vk_sdk 2 | 3 | [![pub package](https://img.shields.io/pub/v/flutter_vk_sdk.svg)](https://pub.dev/packages/flutter_vk_sdk) 4 | 5 | Flutter vk sdk project. 6 | 7 | This plugin is based on: 8 | - Android: [vk-android-sdk v2.1.0](https://github.com/VKCOM/vk-android-sdk/tree/2.1.0) 9 | - iOS: [vk-ios-sdk](https://github.com/VKCOM/vk-ios-sdk) 10 | 11 | ## Installation 12 | 13 | First, add [*`flutter_vk_sdk`*](https://pub.dev/packages/flutter_vk_sdk#-installing-tab-) as a dependency in [your pubspec.yaml file](https://flutter.io/platform-plugins/). 14 | 15 | ``` 16 | flutter_vk_sdk: ^0.0.6+4 17 | ``` 18 | 19 | ### Android 20 | 21 | In your android res/values create strings.xml and fill with this examples 22 | ```xml 23 | 24 | 25 | YOUR_VK_APP_ID 26 | 27 | ``` 28 | 29 | ### iOS 30 | 31 | * AppDelegate 32 | ``` 33 | import UIKit 34 | import Flutter 35 | import VK_ios_sdk 36 | 37 | @UIApplicationMain 38 | @objc class AppDelegate: FlutterAppDelegate { 39 | override func application( 40 | _ application: UIApplication, 41 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? 42 | ) -> Bool { 43 | GeneratedPluginRegistrant.register(with: self) 44 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 45 | } 46 | 47 | override func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { 48 | VKSdk.processOpen(url, fromApplication: "") 49 | return true 50 | } 51 | } 52 | ``` 53 | 54 | * info.plist 55 | ``` 56 | CFBundleURLTypes 57 | 58 | 59 | CFBundleTypeRole 60 | Editor 61 | CFBundleURLName 62 | vk{YOUR_APP_ID} 63 | CFBundleURLSchemes 64 | 65 | vk{YOUR_APP_ID} 66 | 67 | 68 | 69 | 70 | 71 | LSApplicationQueriesSchemes 72 | 73 | vk 74 | vk-share 75 | vkauthorize 76 | 77 | ``` 78 | 79 | ## Dart usage 80 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.kf.flutter_vk_sdk' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | ext.kotlin_version = '1.3.50' 6 | repositories { 7 | google() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:3.5.0' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | } 15 | } 16 | 17 | rootProject.allprojects { 18 | repositories { 19 | google() 20 | jcenter() 21 | } 22 | } 23 | 24 | apply plugin: 'com.android.library' 25 | apply plugin: 'kotlin-android' 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | sourceSets { 31 | main.java.srcDirs += 'src/main/kotlin' 32 | } 33 | defaultConfig { 34 | minSdkVersion 16 35 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 36 | } 37 | lintOptions { 38 | disable 'InvalidPackage' 39 | } 40 | } 41 | 42 | dependencies { 43 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 44 | implementation 'com.vk:androidsdk:2.1.0' 45 | } 46 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'flutter_vk_sdk' 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/kf/flutter_vk_sdk/FlutterVKApiDelegate.kt: -------------------------------------------------------------------------------- 1 | package com.kf.flutter_vk_sdk 2 | 3 | import android.net.Uri 4 | import android.util.Log 5 | 6 | import io.flutter.plugin.common.MethodChannel 7 | 8 | import com.vk.api.sdk.* 9 | import com.vk.api.sdk.exceptions.VKApiExecutionException 10 | import com.vk.api.sdk.internal.ApiCommand 11 | 12 | class FlutterVKApiDelegate { 13 | 14 | private fun finishWithResult(result: MethodChannel.Result, value: String) { 15 | Log.d("VK API DELEGATE", "___________________SET RESULT: $value") 16 | result.success(value) 17 | } 18 | 19 | private fun finishWithError(result: MethodChannel.Result, methodName: String, error: VKApiExecutionException) { 20 | val code = FlutterVKResults.getErrorCode(methodName) 21 | val message = error.errorMsg 22 | val detail = FlutterVKResults.error(error) 23 | Log.d("VK API DELEGATE", "___________________SET ERROR: $code $message $detail") 24 | result.error(code, message, detail) 25 | } 26 | 27 | fun apiMethodCall(arguments: Map, _result: MethodChannel.Result) { 28 | val methodName: String = arguments["method"] as String 29 | Log.d("VK API DELEGATE", "___________________METHOD: $methodName") 30 | var args: Map? = null 31 | if (arguments.containsKey("arguments")) args = arguments["arguments"] as Map 32 | var retryCount: Int? = null 33 | if (arguments.containsKey("retry_count")) retryCount = arguments["retry_count"] as Int 34 | var skipValidation: Boolean? = null 35 | if (arguments.containsKey("skip_validation")) skipValidation = arguments["skip_validation"] as Boolean 36 | 37 | val command = RawApiCommand(methodName, args, retryCount, skipValidation) 38 | VK.execute(command, object : VKApiCallback { 39 | override fun success(result: String) { 40 | finishWithResult(_result, result) 41 | } 42 | 43 | override fun fail(error: VKApiExecutionException) { 44 | finishWithError(_result, methodName, error) 45 | } 46 | }) 47 | } 48 | 49 | fun getPostCommandArguments(arguments: Map?): Map? { 50 | if (arguments == null) return null 51 | return arguments.map { 52 | val value = it.value.toString() 53 | if (value.startsWith("file:///")) Pair(it.key, Uri.parse(value)) 54 | else Pair(it.key, value) 55 | }.toMap() 56 | } 57 | 58 | fun postMethodCall(arguments: Map, _result: MethodChannel.Result) { 59 | val url: String = arguments["url"] as String 60 | Log.d("VK API DELEGATE", "___________________POST URL: $url") 61 | var args: Map? = null 62 | if (arguments.containsKey("arguments")) args = getPostCommandArguments(arguments["arguments"] as Map) 63 | var retryCount: Int? = null 64 | if (arguments.containsKey("retry_count")) retryCount = arguments["retry_count"] as Int 65 | var timeout: Long? = null 66 | if (arguments.containsKey("timeout")) timeout = arguments["timeout"] as Long 67 | val command = RawPostCommand(url, args, retryCount, timeout) 68 | VK.execute(command, object : VKApiCallback { 69 | override fun success(result: String) { 70 | finishWithResult(_result, result) 71 | } 72 | 73 | override fun fail(error: VKApiExecutionException) { 74 | finishWithError(_result, "post_method_call", error) 75 | } 76 | }) 77 | } 78 | } 79 | 80 | 81 | class RawApiCommand(private val method: String, private val args: Map?, 82 | private val retryCount: Int?, private val skipValidation: Boolean?) : ApiCommand() { 83 | companion object { 84 | const val RETRY_COUNT = 3 85 | } 86 | 87 | override fun onExecute(manager: VKApiManager): String { 88 | val callBuilder = VKMethodCall.Builder() 89 | callBuilder.method(method) 90 | callBuilder.version(manager.config.version) 91 | if (args != null) callBuilder.args(args) 92 | 93 | val retryCount = retryCount ?: RETRY_COUNT 94 | callBuilder.retryCount(retryCount) 95 | if (skipValidation != null) callBuilder.skipValidation(skipValidation) 96 | 97 | return manager.execute(callBuilder.build(), RawVKApiResponseParser()) 98 | } 99 | } 100 | 101 | class RawVKApiResponseParser : VKApiResponseParser { 102 | override fun parse(response: String): String { 103 | return response 104 | } 105 | } 106 | 107 | 108 | class RawPostCommand(private val url: String, private val args: Map?, 109 | private val retryCount: Int?, private val timeout: Long?) : ApiCommand() { 110 | companion object { 111 | const val RETRY_COUNT = 3 112 | } 113 | 114 | override fun onExecute(manager: VKApiManager): String { 115 | val callBuilder = VKHttpPostCall.Builder() 116 | callBuilder.url(url) 117 | args?.forEach { (k, v) -> 118 | when (v) { 119 | is Uri -> callBuilder.args(k, v) 120 | is String -> callBuilder.args(k, v) 121 | } 122 | } 123 | 124 | val retryCount = retryCount ?: RETRY_COUNT 125 | callBuilder.retryCount(retryCount) 126 | if (timeout != null) callBuilder.timeout(timeout) 127 | 128 | return manager.execute(callBuilder.build(), null, RawVKApiResponseParser()) 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/kf/flutter_vk_sdk/FlutterVKResultDelegate.kt: -------------------------------------------------------------------------------- 1 | package com.kf.flutter_vk_sdk 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.content.SharedPreferences 6 | import android.util.Log 7 | 8 | import io.flutter.plugin.common.MethodChannel 9 | import io.flutter.plugin.common.PluginRegistry 10 | 11 | import com.vk.api.sdk.auth.VKAccessToken 12 | import com.vk.api.sdk.auth.VKAuthCallback 13 | import com.vk.api.sdk.auth.VKScope 14 | import com.vk.api.sdk.exceptions.VKApiExecutionException 15 | import com.vk.api.sdk.VK 16 | 17 | class FlutterVKSdkDelegate constructor(val registrar: PluginRegistry.Registrar) : PluginRegistry.ActivityResultListener { 18 | private var loginCallback: VKAuthCallback? = null 19 | private var pendingResult: MethodChannel.Result? = null 20 | 21 | companion object { 22 | private const val VK_APP_AUTH_CODE = 282 23 | const val PREFERENCE_NAME = "com.vkontakte.android_pref_name" 24 | const val NEED_LOGIN_ERROR_MSG: String = "NEED_LOGIN" 25 | val defaultScope: Collection = emptySet() 26 | } 27 | 28 | init { 29 | registrar.addActivityResultListener(this) 30 | } 31 | 32 | fun setPendingResult(methodName: String, result: MethodChannel.Result): Boolean { 33 | if (pendingResult != null) { 34 | val message = "$methodName called while another VK operation was in progress." 35 | Log.d("VK DELEGATE", "_______________________CONFLICT ERROR: ${message}") 36 | result.error(getErrorCode("conflict"), message, null) 37 | return false 38 | } 39 | pendingResult = result 40 | return true 41 | } 42 | 43 | private fun getErrorCode(methodName: String): String { 44 | return FlutterVKResults.getErrorCode(methodName) 45 | } 46 | 47 | private fun getCanceledCode(methodName: String): String { 48 | return FlutterVKResults.getCanceledCode(methodName) 49 | } 50 | 51 | private fun clearPending() { 52 | pendingResult = null 53 | loginCallback = null 54 | } 55 | 56 | private fun finishWithResult(result: Any?) { 57 | Log.d("VK DELEGATE", "_______________________SET RESULT: ${result}") 58 | pendingResult?.success(result) 59 | clearPending() 60 | } 61 | 62 | private fun finishWithError(code: String?, message: String?, detail: Any?) { 63 | Log.d("VK DELEGATE", "_______________________SET ERROR: ${code} ${message} ${detail}") 64 | pendingResult?.error(code, message, detail) 65 | clearPending() 66 | } 67 | 68 | fun scopesFromString(scopesStr: String?): Collection { 69 | if (scopesStr == null) return defaultScope 70 | val arr = scopesStr.split(",") 71 | val scopes = arr.map { 72 | val s = it.trim() 73 | VKScope.valueOf(s.toUpperCase()) 74 | } 75 | return scopes 76 | } 77 | 78 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { 79 | if (loginCallback == null) return false 80 | var intent = data 81 | if (intent == null && requestCode == VK_APP_AUTH_CODE) intent = Intent() 82 | return VK.onActivityResult(requestCode, resultCode, intent, loginCallback!!) 83 | } 84 | 85 | // fun initialize(appId: Int, apiVersion: String) { 86 | // if (appId == 0) { 87 | // throw RuntimeException("your_app_id is not found in your resources.xml") 88 | // } 89 | // 90 | // val context = registrar.context() 91 | // VK.setConfig(VKApiConfig( 92 | // context = context, 93 | // appId = appId, 94 | // version = apiVersion, 95 | // validationHandler = VKDefaultValidationHandler(context)) 96 | // ) 97 | // } 98 | 99 | fun isLoggedIn(): Boolean { 100 | return VK.isLoggedIn() 101 | } 102 | 103 | fun getCurrentAccessToken(result: MethodChannel.Result) { 104 | val token = VKAccessToken.restore(getPreferences(registrar.context())) 105 | result.success(FlutterVKResults.accessToken(token)) 106 | } 107 | 108 | fun login(scopes: String?, result: MethodChannel.Result) { 109 | val scopeCollection = scopesFromString(scopes) 110 | val methodName = FlutterVKSdkPlugin.LOGIN_ACTION 111 | if (!setPendingResult(methodName, result)) return 112 | loginCallback = object : VKAuthCallback { 113 | override fun onLogin(token: VKAccessToken) { 114 | finishWithResult(FlutterVKResults.successLogin(token)) 115 | } 116 | 117 | override fun onLoginFailed(errorCode: Int) { 118 | val code = if (errorCode == VKAuthCallback.AUTH_CANCELED) getCanceledCode(methodName) else getErrorCode(methodName) 119 | finishWithError(code, null, null) 120 | } 121 | } 122 | VK.login(registrar.activity(), scopeCollection) 123 | } 124 | 125 | fun logout(result: MethodChannel.Result) { 126 | VK.logout() 127 | result.success(null) 128 | } 129 | 130 | fun isLoggedIn(result: MethodChannel.Result) { 131 | result.success(isLoggedIn()) 132 | } 133 | 134 | fun getPreferences(context: Context): SharedPreferences = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) 135 | } 136 | 137 | object FlutterVKResults { 138 | private const val UNKNOWN_METHOD: String = "UNKNOWN" 139 | 140 | fun getErrorCode(methodName: String): String { 141 | var name = methodName 142 | if (name.isEmpty()) name = UNKNOWN_METHOD 143 | return "${name.toLowerCase()}_error" 144 | } 145 | 146 | fun getCanceledCode(methodName: String): String { 147 | var name = methodName 148 | if (name.isEmpty()) name = UNKNOWN_METHOD 149 | return "${name.toLowerCase()}_canceled" 150 | } 151 | 152 | fun successLogin(token: VKAccessToken): Map? { 153 | return accessToken(token) 154 | } 155 | 156 | fun error(error: VKApiExecutionException): Map { 157 | val res = HashMap() 158 | res["code"] = error.code 159 | res["apiMethod"] = error.apiMethod 160 | res["hasLocalizedMessage"] = error.hasLocalizedMessage 161 | res["errorMsg"] = error.errorMsg 162 | res["detailMessage"] = error.message 163 | if (error.extra != null) res["extra"] = error.extra.toString() 164 | if (error.executeErrors != null) 165 | res["executeErrors"] = error.executeErrors?.map { error(it) }?.joinToString(prefix = "[", postfix = "]") 166 | return res 167 | } 168 | 169 | fun accessToken(token: VKAccessToken?): Map? { 170 | if (token == null) return null 171 | return mapOf( 172 | "token" to token.accessToken, 173 | "userId" to token.userId, 174 | "secret" to token.secret, 175 | "email" to token.email, 176 | "phone" to token.phone, 177 | "phoneAccessKey" to token.phoneAccessKey, 178 | "created" to token.created 179 | ) 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/kf/flutter_vk_sdk/FlutterVKSdkPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.kf.flutter_vk_sdk 2 | 3 | import android.util.Log 4 | 5 | import io.flutter.plugin.common.MethodCall 6 | import io.flutter.plugin.common.MethodChannel 7 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler 8 | import io.flutter.plugin.common.MethodChannel.Result 9 | import io.flutter.plugin.common.PluginRegistry.Registrar 10 | 11 | class FlutterVKSdkPlugin : MethodCallHandler { 12 | 13 | private var delegate: FlutterVKSdkDelegate 14 | private var apiDelegate: FlutterVKApiDelegate 15 | 16 | constructor(registrar: Registrar) { 17 | Log.d("VK PLUGIN", "_________________________CALL CONSTRUCTOR") 18 | delegate = FlutterVKSdkDelegate(registrar) 19 | apiDelegate = FlutterVKApiDelegate() 20 | } 21 | 22 | companion object { 23 | private const val CHANNEL_NAME: String = "com.fb.fluttervksdk/vk" 24 | const val APP_ID_ARGUMENT: String = "app_id" 25 | const val API_VERSION_ARGUMENT: String = "api_version" 26 | const val SCOPE_ARGUMENT: String = "scope" 27 | 28 | const val INITIALIZE_ACTION: String = "initialize" 29 | const val IS_LOGGED_IN_ACTION: String = "is_logged_in" 30 | const val LOGIN_ACTION: String = "login" 31 | const val LOGOUT_ACTION: String = "logout" 32 | const val GET_ACCESS_TOKEN_ACTION: String = "get_access_token" 33 | const val API_ACTION: String = "api_method_call" 34 | const val POST_ACTION: String = "post_method_call" 35 | 36 | @JvmStatic 37 | fun registerWith(registrar: Registrar) { 38 | val channel = MethodChannel(registrar.messenger(), CHANNEL_NAME) 39 | channel.setMethodCallHandler(FlutterVKSdkPlugin(registrar)) 40 | } 41 | } 42 | 43 | override fun onMethodCall(call: MethodCall, result: Result) { 44 | Log.d("VK PLUGIN", "_________________________CALL METHOD: ${call.method}") 45 | when (call.method) { 46 | // INITIALIZE_ACTION -> { 47 | // val appIdArg: String? = call.argument(APP_ID_ARGUMENT) 48 | // val appId = appIdArg?.toInt() ?: 0 49 | // val apiVersion: String = call.argument(API_VERSION_ARGUMENT) ?: "" 50 | // delegate.initialize(appId, apiVersion) 51 | // result.success(null) 52 | // } 53 | LOGIN_ACTION -> { 54 | val scope: String? = call.argument(SCOPE_ARGUMENT) 55 | delegate.login(scope, result) 56 | } 57 | LOGOUT_ACTION -> { 58 | delegate.logout(result) 59 | } 60 | IS_LOGGED_IN_ACTION -> { 61 | delegate.isLoggedIn(result) 62 | } 63 | GET_ACCESS_TOKEN_ACTION -> { 64 | delegate.getCurrentAccessToken(result) 65 | } 66 | API_ACTION -> { 67 | val arguments = call.arguments>() 68 | apiDelegate.apiMethodCall(arguments, result) 69 | } 70 | POST_ACTION -> { 71 | val arguments = call.arguments>() 72 | apiDelegate.postMethodCall(arguments, result) 73 | } 74 | else -> { 75 | result.notImplemented() 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .packages 26 | .pub-cache/ 27 | .pub/ 28 | /build/ 29 | 30 | # Android related 31 | **/android/**/gradle-wrapper.jar 32 | **/android/.gradle 33 | **/android/captures/ 34 | **/android/gradlew 35 | **/android/gradlew.bat 36 | **/android/local.properties 37 | **/android/**/GeneratedPluginRegistrant.java 38 | 39 | # iOS/XCode related 40 | **/ios/**/*.mode1v3 41 | **/ios/**/*.mode2v3 42 | **/ios/**/*.moved-aside 43 | **/ios/**/*.pbxuser 44 | **/ios/**/*.perspectivev3 45 | **/ios/**/*sync/ 46 | **/ios/**/.sconsign.dblite 47 | **/ios/**/.tags* 48 | **/ios/**/.vagrant/ 49 | **/ios/**/DerivedData/ 50 | **/ios/**/Icon? 51 | **/ios/**/Pods/ 52 | **/ios/**/.symlinks/ 53 | **/ios/**/profile 54 | **/ios/**/xcuserdata 55 | **/ios/.generated/ 56 | **/ios/Flutter/App.framework 57 | **/ios/Flutter/Flutter.framework 58 | **/ios/Flutter/Generated.xcconfig 59 | **/ios/Flutter/app.flx 60 | **/ios/Flutter/app.zip 61 | **/ios/Flutter/flutter_assets/ 62 | **/ios/ServiceDefinitions.json 63 | **/ios/Runner/GeneratedPluginRegistrant.* 64 | 65 | # Exceptions to above rules. 66 | !**/ios/**/default.mode1v3 67 | !**/ios/**/default.mode2v3 68 | !**/ios/**/default.pbxuser 69 | !**/ios/**/default.perspectivev3 70 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 71 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # flutter_vk_sdk_example 2 | 3 | Demonstrates how to use the flutter_vk_sdk plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | apply plugin: 'com.android.application' 24 | apply plugin: 'kotlin-android' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | 28 | android { 29 | compileSdkVersion 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.kf.flutter_vk_sdk_example" 42 | minSdkVersion 16 43 | targetSdkVersion 28 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 47 | } 48 | 49 | buildTypes { 50 | release { 51 | // TODO: Add your own signing config for the release build. 52 | // Signing with the debug keys for now, so `flutter run --release` works. 53 | signingConfig signingConfigs.debug 54 | } 55 | } 56 | } 57 | 58 | flutter { 59 | source '../..' 60 | } 61 | 62 | dependencies { 63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 64 | testImplementation 'junit:junit:4.12' 65 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 66 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 67 | } 68 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 13 | 20 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/kf/flutter_vk_sdk_example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kf.flutter_vk_sdk_example 2 | 3 | import android.os.Bundle 4 | 5 | import io.flutter.app.FlutterActivity 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | GeneratedPluginRegistrant.registerWith(this) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7012114 4 | 5 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.2.71' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.2.1' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | pods_ary = [] 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) { |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | pods_ary.push({:name => podname, :path => podpath}); 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | } 32 | return pods_ary 33 | end 34 | 35 | target 'Runner' do 36 | use_frameworks! 37 | 38 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 39 | # referring to absolute paths on developers' machines. 40 | system('rm -rf .symlinks') 41 | system('mkdir -p .symlinks/plugins') 42 | 43 | # Flutter Pods 44 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') 45 | if generated_xcode_build_settings.empty? 46 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." 47 | end 48 | generated_xcode_build_settings.map { |p| 49 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR' 50 | symlink = File.join('.symlinks', 'flutter') 51 | File.symlink(File.dirname(p[:path]), symlink) 52 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) 53 | end 54 | } 55 | 56 | # Plugin Pods 57 | plugin_pods = parse_KV_file('../.flutter-plugins') 58 | plugin_pods.map { |p| 59 | symlink = File.join('.symlinks', 'plugins', p[:name]) 60 | File.symlink(p[:path], symlink) 61 | pod p[:name], :path => File.join(symlink, 'ios') 62 | } 63 | end 64 | 65 | post_install do |installer| 66 | installer.pods_project.targets.each do |target| 67 | target.build_configurations.each do |config| 68 | config.build_settings['ENABLE_BITCODE'] = 'NO' 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - camera_utils (0.0.1): 3 | - Flutter 4 | - Flutter (1.0.0) 5 | - flutter_vk_sdk (0.0.1): 6 | - Flutter 7 | - VK-ios-sdk 8 | - VK-ios-sdk (1.4.6) 9 | 10 | DEPENDENCIES: 11 | - camera_utils (from `.symlinks/plugins/camera_utils/ios`) 12 | - Flutter (from `.symlinks/flutter/ios`) 13 | - flutter_vk_sdk (from `.symlinks/plugins/flutter_vk_sdk/ios`) 14 | 15 | SPEC REPOS: 16 | https://github.com/CocoaPods/Specs.git: 17 | - VK-ios-sdk 18 | 19 | EXTERNAL SOURCES: 20 | camera_utils: 21 | :path: ".symlinks/plugins/camera_utils/ios" 22 | Flutter: 23 | :path: ".symlinks/flutter/ios" 24 | flutter_vk_sdk: 25 | :path: ".symlinks/plugins/flutter_vk_sdk/ios" 26 | 27 | SPEC CHECKSUMS: 28 | camera_utils: b5d2bd7da92bd60a32700bc506691ff47100e071 29 | Flutter: 9d0fac939486c9aba2809b7982dfdbb47a7b0296 30 | flutter_vk_sdk: 1d8f28dec83f1d70b5924ccd052521c6e75ec281 31 | VK-ios-sdk: 7fd48bc5aaa6b96c3197c1987eb6593f2ea67331 32 | 33 | PODFILE CHECKSUM: ebd43b443038e611b86ede96e613bd6033c49497 34 | 35 | COCOAPODS: 1.5.0 36 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 15 | 798D454FE70A7965182C7EAA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A68DE9D15C31CC9B5E0F3645 /* Pods_Runner.framework */; }; 16 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 17 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 18 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 19 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 20 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 21 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXCopyFilesBuildPhase section */ 25 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 26 | isa = PBXCopyFilesBuildPhase; 27 | buildActionMask = 2147483647; 28 | dstPath = ""; 29 | dstSubfolderSpec = 10; 30 | files = ( 31 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 32 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 33 | ); 34 | name = "Embed Frameworks"; 35 | runOnlyForDeploymentPostprocessing = 0; 36 | }; 37 | /* End PBXCopyFilesBuildPhase section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 41 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 42 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 43 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 44 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 45 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 47 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 48 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 49 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 50 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 52 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 53 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 54 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | A68DE9D15C31CC9B5E0F3645 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 64 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 65 | 798D454FE70A7965182C7EAA /* Pods_Runner.framework in Frameworks */, 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXFrameworksBuildPhase section */ 70 | 71 | /* Begin PBXGroup section */ 72 | 56D8F44B57F70FF3D10BD050 /* Pods */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | ); 76 | name = Pods; 77 | sourceTree = ""; 78 | }; 79 | 9740EEB11CF90186004384FC /* Flutter */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 3B80C3931E831B6300D905FE /* App.framework */, 83 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 84 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 85 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 86 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 87 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 88 | ); 89 | name = Flutter; 90 | sourceTree = ""; 91 | }; 92 | 97C146E51CF9000F007C117D = { 93 | isa = PBXGroup; 94 | children = ( 95 | 9740EEB11CF90186004384FC /* Flutter */, 96 | 97C146F01CF9000F007C117D /* Runner */, 97 | 97C146EF1CF9000F007C117D /* Products */, 98 | 56D8F44B57F70FF3D10BD050 /* Pods */, 99 | CE91032063520C280EAF7210 /* Frameworks */, 100 | ); 101 | sourceTree = ""; 102 | }; 103 | 97C146EF1CF9000F007C117D /* Products */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 97C146EE1CF9000F007C117D /* Runner.app */, 107 | ); 108 | name = Products; 109 | sourceTree = ""; 110 | }; 111 | 97C146F01CF9000F007C117D /* Runner */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 115 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 116 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 117 | 97C147021CF9000F007C117D /* Info.plist */, 118 | 97C146F11CF9000F007C117D /* Supporting Files */, 119 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 120 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 121 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 122 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 123 | ); 124 | path = Runner; 125 | sourceTree = ""; 126 | }; 127 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | ); 131 | name = "Supporting Files"; 132 | sourceTree = ""; 133 | }; 134 | CE91032063520C280EAF7210 /* Frameworks */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | A68DE9D15C31CC9B5E0F3645 /* Pods_Runner.framework */, 138 | ); 139 | name = Frameworks; 140 | sourceTree = ""; 141 | }; 142 | /* End PBXGroup section */ 143 | 144 | /* Begin PBXNativeTarget section */ 145 | 97C146ED1CF9000F007C117D /* Runner */ = { 146 | isa = PBXNativeTarget; 147 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 148 | buildPhases = ( 149 | 450A5623381377034A3109C3 /* [CP] Check Pods Manifest.lock */, 150 | 9740EEB61CF901F6004384FC /* Run Script */, 151 | 97C146EA1CF9000F007C117D /* Sources */, 152 | 97C146EB1CF9000F007C117D /* Frameworks */, 153 | 97C146EC1CF9000F007C117D /* Resources */, 154 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 155 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 156 | BD60D1FF34A037DDFF038090 /* [CP] Embed Pods Frameworks */, 157 | ); 158 | buildRules = ( 159 | ); 160 | dependencies = ( 161 | ); 162 | name = Runner; 163 | productName = Runner; 164 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 165 | productType = "com.apple.product-type.application"; 166 | }; 167 | /* End PBXNativeTarget section */ 168 | 169 | /* Begin PBXProject section */ 170 | 97C146E61CF9000F007C117D /* Project object */ = { 171 | isa = PBXProject; 172 | attributes = { 173 | LastUpgradeCheck = 0910; 174 | ORGANIZATIONNAME = "The Chromium Authors"; 175 | TargetAttributes = { 176 | 97C146ED1CF9000F007C117D = { 177 | CreatedOnToolsVersion = 7.3.1; 178 | DevelopmentTeam = NRB7B49KV8; 179 | LastSwiftMigration = 0910; 180 | SystemCapabilities = { 181 | com.apple.BackgroundModes = { 182 | enabled = 1; 183 | }; 184 | }; 185 | }; 186 | }; 187 | }; 188 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 189 | compatibilityVersion = "Xcode 3.2"; 190 | developmentRegion = English; 191 | hasScannedForEncodings = 0; 192 | knownRegions = ( 193 | English, 194 | en, 195 | Base, 196 | ); 197 | mainGroup = 97C146E51CF9000F007C117D; 198 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 199 | projectDirPath = ""; 200 | projectRoot = ""; 201 | targets = ( 202 | 97C146ED1CF9000F007C117D /* Runner */, 203 | ); 204 | }; 205 | /* End PBXProject section */ 206 | 207 | /* Begin PBXResourcesBuildPhase section */ 208 | 97C146EC1CF9000F007C117D /* Resources */ = { 209 | isa = PBXResourcesBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 213 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 214 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 215 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 216 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 217 | ); 218 | runOnlyForDeploymentPostprocessing = 0; 219 | }; 220 | /* End PBXResourcesBuildPhase section */ 221 | 222 | /* Begin PBXShellScriptBuildPhase section */ 223 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 224 | isa = PBXShellScriptBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | ); 228 | inputPaths = ( 229 | ); 230 | name = "Thin Binary"; 231 | outputPaths = ( 232 | ); 233 | runOnlyForDeploymentPostprocessing = 0; 234 | shellPath = /bin/sh; 235 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 236 | }; 237 | 450A5623381377034A3109C3 /* [CP] Check Pods Manifest.lock */ = { 238 | isa = PBXShellScriptBuildPhase; 239 | buildActionMask = 2147483647; 240 | files = ( 241 | ); 242 | inputPaths = ( 243 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 244 | "${PODS_ROOT}/Manifest.lock", 245 | ); 246 | name = "[CP] Check Pods Manifest.lock"; 247 | outputPaths = ( 248 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | shellPath = /bin/sh; 252 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 253 | showEnvVarsInLog = 0; 254 | }; 255 | 9740EEB61CF901F6004384FC /* Run Script */ = { 256 | isa = PBXShellScriptBuildPhase; 257 | buildActionMask = 2147483647; 258 | files = ( 259 | ); 260 | inputPaths = ( 261 | ); 262 | name = "Run Script"; 263 | outputPaths = ( 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | shellPath = /bin/sh; 267 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 268 | }; 269 | BD60D1FF34A037DDFF038090 /* [CP] Embed Pods Frameworks */ = { 270 | isa = PBXShellScriptBuildPhase; 271 | buildActionMask = 2147483647; 272 | files = ( 273 | ); 274 | inputPaths = ( 275 | "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", 276 | "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", 277 | "${BUILT_PRODUCTS_DIR}/VK-ios-sdk/VK_ios_sdk.framework", 278 | "${BUILT_PRODUCTS_DIR}/camera_utils/camera_utils.framework", 279 | "${BUILT_PRODUCTS_DIR}/flutter_vk_sdk/flutter_vk_sdk.framework", 280 | ); 281 | name = "[CP] Embed Pods Frameworks"; 282 | outputPaths = ( 283 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", 284 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/VK_ios_sdk.framework", 285 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/camera_utils.framework", 286 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_vk_sdk.framework", 287 | ); 288 | runOnlyForDeploymentPostprocessing = 0; 289 | shellPath = /bin/sh; 290 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 291 | showEnvVarsInLog = 0; 292 | }; 293 | /* End PBXShellScriptBuildPhase section */ 294 | 295 | /* Begin PBXSourcesBuildPhase section */ 296 | 97C146EA1CF9000F007C117D /* Sources */ = { 297 | isa = PBXSourcesBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 301 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 302 | ); 303 | runOnlyForDeploymentPostprocessing = 0; 304 | }; 305 | /* End PBXSourcesBuildPhase section */ 306 | 307 | /* Begin PBXVariantGroup section */ 308 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 309 | isa = PBXVariantGroup; 310 | children = ( 311 | 97C146FB1CF9000F007C117D /* Base */, 312 | ); 313 | name = Main.storyboard; 314 | sourceTree = ""; 315 | }; 316 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 317 | isa = PBXVariantGroup; 318 | children = ( 319 | 97C147001CF9000F007C117D /* Base */, 320 | ); 321 | name = LaunchScreen.storyboard; 322 | sourceTree = ""; 323 | }; 324 | /* End PBXVariantGroup section */ 325 | 326 | /* Begin XCBuildConfiguration section */ 327 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 328 | isa = XCBuildConfiguration; 329 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 330 | buildSettings = { 331 | ALWAYS_SEARCH_USER_PATHS = NO; 332 | CLANG_ANALYZER_NONNULL = YES; 333 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 334 | CLANG_CXX_LIBRARY = "libc++"; 335 | CLANG_ENABLE_MODULES = YES; 336 | CLANG_ENABLE_OBJC_ARC = YES; 337 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 338 | CLANG_WARN_BOOL_CONVERSION = YES; 339 | CLANG_WARN_COMMA = YES; 340 | CLANG_WARN_CONSTANT_CONVERSION = YES; 341 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 342 | CLANG_WARN_EMPTY_BODY = YES; 343 | CLANG_WARN_ENUM_CONVERSION = YES; 344 | CLANG_WARN_INFINITE_RECURSION = YES; 345 | CLANG_WARN_INT_CONVERSION = YES; 346 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 347 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 348 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 349 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 350 | CLANG_WARN_STRICT_PROTOTYPES = YES; 351 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 352 | CLANG_WARN_UNREACHABLE_CODE = YES; 353 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 354 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 355 | COPY_PHASE_STRIP = NO; 356 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 357 | ENABLE_NS_ASSERTIONS = NO; 358 | ENABLE_STRICT_OBJC_MSGSEND = YES; 359 | GCC_C_LANGUAGE_STANDARD = gnu99; 360 | GCC_NO_COMMON_BLOCKS = YES; 361 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 362 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 363 | GCC_WARN_UNDECLARED_SELECTOR = YES; 364 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 365 | GCC_WARN_UNUSED_FUNCTION = YES; 366 | GCC_WARN_UNUSED_VARIABLE = YES; 367 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 368 | MTL_ENABLE_DEBUG_INFO = NO; 369 | SDKROOT = iphoneos; 370 | TARGETED_DEVICE_FAMILY = "1,2"; 371 | VALIDATE_PRODUCT = YES; 372 | }; 373 | name = Profile; 374 | }; 375 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 376 | isa = XCBuildConfiguration; 377 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 378 | buildSettings = { 379 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 380 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 381 | DEVELOPMENT_TEAM = NRB7B49KV8; 382 | ENABLE_BITCODE = NO; 383 | FRAMEWORK_SEARCH_PATHS = ( 384 | "$(inherited)", 385 | "$(PROJECT_DIR)/Flutter", 386 | ); 387 | INFOPLIST_FILE = Runner/Info.plist; 388 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 389 | LIBRARY_SEARCH_PATHS = ( 390 | "$(inherited)", 391 | "$(PROJECT_DIR)/Flutter", 392 | ); 393 | PRODUCT_BUNDLE_IDENTIFIER = com.kf.flutterVKSdkExample; 394 | PRODUCT_NAME = "$(TARGET_NAME)"; 395 | SWIFT_VERSION = 4.0; 396 | VERSIONING_SYSTEM = "apple-generic"; 397 | }; 398 | name = Profile; 399 | }; 400 | 97C147031CF9000F007C117D /* Debug */ = { 401 | isa = XCBuildConfiguration; 402 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 403 | buildSettings = { 404 | ALWAYS_SEARCH_USER_PATHS = NO; 405 | CLANG_ANALYZER_NONNULL = YES; 406 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 407 | CLANG_CXX_LIBRARY = "libc++"; 408 | CLANG_ENABLE_MODULES = YES; 409 | CLANG_ENABLE_OBJC_ARC = YES; 410 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 411 | CLANG_WARN_BOOL_CONVERSION = YES; 412 | CLANG_WARN_COMMA = YES; 413 | CLANG_WARN_CONSTANT_CONVERSION = YES; 414 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 415 | CLANG_WARN_EMPTY_BODY = YES; 416 | CLANG_WARN_ENUM_CONVERSION = YES; 417 | CLANG_WARN_INFINITE_RECURSION = YES; 418 | CLANG_WARN_INT_CONVERSION = YES; 419 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 420 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 421 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 422 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 423 | CLANG_WARN_STRICT_PROTOTYPES = YES; 424 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 425 | CLANG_WARN_UNREACHABLE_CODE = YES; 426 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 427 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 428 | COPY_PHASE_STRIP = NO; 429 | DEBUG_INFORMATION_FORMAT = dwarf; 430 | ENABLE_STRICT_OBJC_MSGSEND = YES; 431 | ENABLE_TESTABILITY = YES; 432 | GCC_C_LANGUAGE_STANDARD = gnu99; 433 | GCC_DYNAMIC_NO_PIC = NO; 434 | GCC_NO_COMMON_BLOCKS = YES; 435 | GCC_OPTIMIZATION_LEVEL = 0; 436 | GCC_PREPROCESSOR_DEFINITIONS = ( 437 | "DEBUG=1", 438 | "$(inherited)", 439 | ); 440 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 441 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 442 | GCC_WARN_UNDECLARED_SELECTOR = YES; 443 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 444 | GCC_WARN_UNUSED_FUNCTION = YES; 445 | GCC_WARN_UNUSED_VARIABLE = YES; 446 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 447 | MTL_ENABLE_DEBUG_INFO = YES; 448 | ONLY_ACTIVE_ARCH = YES; 449 | SDKROOT = iphoneos; 450 | TARGETED_DEVICE_FAMILY = "1,2"; 451 | }; 452 | name = Debug; 453 | }; 454 | 97C147041CF9000F007C117D /* Release */ = { 455 | isa = XCBuildConfiguration; 456 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 457 | buildSettings = { 458 | ALWAYS_SEARCH_USER_PATHS = NO; 459 | CLANG_ANALYZER_NONNULL = YES; 460 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 461 | CLANG_CXX_LIBRARY = "libc++"; 462 | CLANG_ENABLE_MODULES = YES; 463 | CLANG_ENABLE_OBJC_ARC = YES; 464 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 465 | CLANG_WARN_BOOL_CONVERSION = YES; 466 | CLANG_WARN_COMMA = YES; 467 | CLANG_WARN_CONSTANT_CONVERSION = YES; 468 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 469 | CLANG_WARN_EMPTY_BODY = YES; 470 | CLANG_WARN_ENUM_CONVERSION = YES; 471 | CLANG_WARN_INFINITE_RECURSION = YES; 472 | CLANG_WARN_INT_CONVERSION = YES; 473 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 474 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 475 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 476 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 477 | CLANG_WARN_STRICT_PROTOTYPES = YES; 478 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 479 | CLANG_WARN_UNREACHABLE_CODE = YES; 480 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 481 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 482 | COPY_PHASE_STRIP = NO; 483 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 484 | ENABLE_NS_ASSERTIONS = NO; 485 | ENABLE_STRICT_OBJC_MSGSEND = YES; 486 | GCC_C_LANGUAGE_STANDARD = gnu99; 487 | GCC_NO_COMMON_BLOCKS = YES; 488 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 489 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 490 | GCC_WARN_UNDECLARED_SELECTOR = YES; 491 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 492 | GCC_WARN_UNUSED_FUNCTION = YES; 493 | GCC_WARN_UNUSED_VARIABLE = YES; 494 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 495 | MTL_ENABLE_DEBUG_INFO = NO; 496 | SDKROOT = iphoneos; 497 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 498 | TARGETED_DEVICE_FAMILY = "1,2"; 499 | VALIDATE_PRODUCT = YES; 500 | }; 501 | name = Release; 502 | }; 503 | 97C147061CF9000F007C117D /* Debug */ = { 504 | isa = XCBuildConfiguration; 505 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 506 | buildSettings = { 507 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 508 | CLANG_ENABLE_MODULES = YES; 509 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 510 | DEVELOPMENT_TEAM = NRB7B49KV8; 511 | ENABLE_BITCODE = NO; 512 | FRAMEWORK_SEARCH_PATHS = ( 513 | "$(inherited)", 514 | "$(PROJECT_DIR)/Flutter", 515 | ); 516 | INFOPLIST_FILE = Runner/Info.plist; 517 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 518 | LIBRARY_SEARCH_PATHS = ( 519 | "$(inherited)", 520 | "$(PROJECT_DIR)/Flutter", 521 | ); 522 | PRODUCT_BUNDLE_IDENTIFIER = com.kf.flutterVKSdkExample; 523 | PRODUCT_NAME = "$(TARGET_NAME)"; 524 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 525 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 526 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 527 | SWIFT_VERSION = 4.0; 528 | VERSIONING_SYSTEM = "apple-generic"; 529 | }; 530 | name = Debug; 531 | }; 532 | 97C147071CF9000F007C117D /* Release */ = { 533 | isa = XCBuildConfiguration; 534 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 535 | buildSettings = { 536 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 537 | CLANG_ENABLE_MODULES = YES; 538 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 539 | DEVELOPMENT_TEAM = NRB7B49KV8; 540 | ENABLE_BITCODE = NO; 541 | FRAMEWORK_SEARCH_PATHS = ( 542 | "$(inherited)", 543 | "$(PROJECT_DIR)/Flutter", 544 | ); 545 | INFOPLIST_FILE = Runner/Info.plist; 546 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 547 | LIBRARY_SEARCH_PATHS = ( 548 | "$(inherited)", 549 | "$(PROJECT_DIR)/Flutter", 550 | ); 551 | PRODUCT_BUNDLE_IDENTIFIER = com.kf.flutterVKSdkExample; 552 | PRODUCT_NAME = "$(TARGET_NAME)"; 553 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 554 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 555 | SWIFT_VERSION = 4.0; 556 | VERSIONING_SYSTEM = "apple-generic"; 557 | }; 558 | name = Release; 559 | }; 560 | /* End XCBuildConfiguration section */ 561 | 562 | /* Begin XCConfigurationList section */ 563 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 564 | isa = XCConfigurationList; 565 | buildConfigurations = ( 566 | 97C147031CF9000F007C117D /* Debug */, 567 | 97C147041CF9000F007C117D /* Release */, 568 | 249021D3217E4FDB00AE95B9 /* Profile */, 569 | ); 570 | defaultConfigurationIsVisible = 0; 571 | defaultConfigurationName = Release; 572 | }; 573 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 574 | isa = XCConfigurationList; 575 | buildConfigurations = ( 576 | 97C147061CF9000F007C117D /* Debug */, 577 | 97C147071CF9000F007C117D /* Release */, 578 | 249021D4217E4FDB00AE95B9 /* Profile */, 579 | ); 580 | defaultConfigurationIsVisible = 0; 581 | defaultConfigurationName = Release; 582 | }; 583 | /* End XCConfigurationList section */ 584 | }; 585 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 586 | } 587 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | import VK_ios_sdk 4 | 5 | @UIApplicationMain 6 | @objc class AppDelegate: FlutterAppDelegate { 7 | override func application( 8 | _ application: UIApplication, 9 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? 10 | ) -> Bool { 11 | GeneratedPluginRegistrant.register(with: self) 12 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 13 | } 14 | 15 | override func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { 16 | VKSdk.processOpen(url, fromApplication: "") 17 | return true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_vk_sdk_example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleURLTypes 22 | 23 | 24 | CFBundleTypeRole 25 | Editor 26 | CFBundleURLName 27 | vk7012114 28 | CFBundleURLSchemes 29 | 30 | vk7012114 31 | 32 | 33 | 34 | CFBundleVersion 35 | $(FLUTTER_BUILD_NUMBER) 36 | LSApplicationQueriesSchemes 37 | 38 | vk 39 | vk-share 40 | vkauthorize 41 | 42 | LSRequiresIPhoneOS 43 | 44 | NSAppTransportSecurity 45 | 46 | NSExceptionDomains 47 | 48 | vk.com 49 | 50 | NSExceptionAllowsInsecureHTTPLoads 51 | 52 | NSExceptionRequiresForwardSecrecy 53 | 54 | NSIncludesSubdomains 55 | 56 | 57 | 58 | 59 | NSPhotoLibraryUsageDescription 60 | Gallery 61 | NSCameraUsageDescription 62 | Camera 63 | NSMicrophoneUsageDescription 64 | Microphone 65 | UIBackgroundModes 66 | 67 | fetch 68 | remote-notification 69 | 70 | UILaunchStoryboardName 71 | LaunchScreen 72 | UIMainStoryboardFile 73 | Main 74 | UISupportedInterfaceOrientations 75 | 76 | UIInterfaceOrientationPortrait 77 | UIInterfaceOrientationLandscapeLeft 78 | UIInterfaceOrientationLandscapeRight 79 | 80 | UISupportedInterfaceOrientations~ipad 81 | 82 | UIInterfaceOrientationPortrait 83 | UIInterfaceOrientationPortraitUpsideDown 84 | UIInterfaceOrientationLandscapeLeft 85 | UIInterfaceOrientationLandscapeRight 86 | 87 | UIViewControllerBasedStatusBarAppearance 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_vk_sdk/flutter_vk_sdk.dart'; 3 | import 'package:flutter_vk_sdk/models/attachment.dart'; 4 | import 'package:flutter_vk_sdk/vk_scope.dart'; 5 | 6 | import 'package:camera_utils/camera_utils.dart'; 7 | 8 | void main() { 9 | initVKSdk(); 10 | runApp(MaterialApp(home: MyApp())); 11 | } 12 | 13 | initVKSdk() { 14 | return FlutterVKSdk.init(appId: '7012114'); 15 | } 16 | 17 | class MyApp extends StatefulWidget { 18 | @override 19 | _MyAppState createState() => _MyAppState(); 20 | } 21 | 22 | class _MyAppState extends State { 23 | String _value = 'unknown'; 24 | 25 | @override 26 | void initState() { 27 | super.initState(); 28 | } 29 | 30 | checkLoggedIn() async { 31 | var isLoggedIn = await FlutterVKSdk.isLoggedIn(); 32 | setState(() { 33 | _value = isLoggedIn.toString(); 34 | }); 35 | } 36 | 37 | void vkLogin() async { 38 | FlutterVKSdk.login( 39 | scope: '${VKScope.wall}, ${VKScope.photos}, ${VKScope.video}', 40 | onSuccess: (res) { 41 | setState(() { 42 | _value = 'true'; 43 | }); 44 | }, 45 | onError: (error) { 46 | print('LOGIN ERROR: $error}'); 47 | setState(() { 48 | _value = 'error'; 49 | }); 50 | }, 51 | ); 52 | } 53 | 54 | vkShare() async { 55 | FlutterVKSdk.shareWithDialog( 56 | context: context, 57 | text: 'Some post text.\n#HASHTAG', 58 | addAttachments: addAttachments, 59 | onSuccess: handleShareSuccess, 60 | onError: handleShareError, 61 | ); 62 | } 63 | 64 | Future> addAttachments(AttachmentType type) async { 65 | String path; 66 | String thumbnail; 67 | if (type == AttachmentType.photo) { 68 | path = await CameraUtils.pickImage; 69 | } else if (type == AttachmentType.video) { 70 | path = await CameraUtils.pickVideo; 71 | if (path != null) thumbnail = await CameraUtils.getThumbnail(path); 72 | } 73 | 74 | if (path == null) return null; 75 | return [Attachment(type, path, thumbnail: thumbnail)]; 76 | } 77 | 78 | @override 79 | Widget build(BuildContext context) { 80 | return Scaffold( 81 | appBar: AppBar( 82 | title: const Text('Plugin example app'), 83 | leading: FlatButton( 84 | onPressed: vkLogin, 85 | child: Icon(Icons.input), 86 | ), 87 | actions: [ 88 | FlatButton( 89 | onPressed: vkShare, 90 | child: Icon(Icons.share), 91 | ) 92 | ], 93 | ), 94 | floatingActionButton: FloatingActionButton(onPressed: logout, child: Icon(Icons.close)), 95 | body: Center( 96 | child: Text('LoggedIn: $_value\n'), 97 | ), 98 | ); 99 | } 100 | 101 | handleShareSuccess(res) { 102 | print('SUCCESS: $res}'); 103 | setState(() { 104 | _value = 'true'; 105 | }); 106 | } 107 | 108 | handleShareError(error) { 109 | print('SHARE ERROR: $error}'); 110 | setState(() { 111 | _value = 'error'; 112 | }); 113 | } 114 | 115 | logout() { 116 | FlutterVKSdk.logout(); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.1.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.0.4" 18 | camera_utils: 19 | dependency: "direct main" 20 | description: 21 | name: camera_utils 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "0.1.8" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.1.2" 32 | collection: 33 | dependency: transitive 34 | description: 35 | name: collection 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.14.11" 39 | cupertino_icons: 40 | dependency: "direct main" 41 | description: 42 | name: cupertino_icons 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "0.1.2" 46 | flutter: 47 | dependency: "direct main" 48 | description: flutter 49 | source: sdk 50 | version: "0.0.0" 51 | flutter_test: 52 | dependency: "direct dev" 53 | description: flutter 54 | source: sdk 55 | version: "0.0.0" 56 | flutter_vk_sdk: 57 | dependency: "direct dev" 58 | description: 59 | path: ".." 60 | relative: true 61 | source: path 62 | version: "0.0.6+3" 63 | http: 64 | dependency: transitive 65 | description: 66 | name: http 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "0.12.0+2" 70 | http_parser: 71 | dependency: transitive 72 | description: 73 | name: http_parser 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "3.1.3" 77 | matcher: 78 | dependency: transitive 79 | description: 80 | name: matcher 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "0.12.5" 84 | meta: 85 | dependency: transitive 86 | description: 87 | name: meta 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "1.1.6" 91 | path: 92 | dependency: transitive 93 | description: 94 | name: path 95 | url: "https://pub.dartlang.org" 96 | source: hosted 97 | version: "1.6.2" 98 | pedantic: 99 | dependency: transitive 100 | description: 101 | name: pedantic 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "1.5.0" 105 | quiver: 106 | dependency: transitive 107 | description: 108 | name: quiver 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "2.0.2" 112 | sky_engine: 113 | dependency: transitive 114 | description: flutter 115 | source: sdk 116 | version: "0.0.99" 117 | source_span: 118 | dependency: transitive 119 | description: 120 | name: source_span 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.5.5" 124 | stack_trace: 125 | dependency: transitive 126 | description: 127 | name: stack_trace 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.9.3" 131 | stream_channel: 132 | dependency: transitive 133 | description: 134 | name: stream_channel 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "2.0.0" 138 | string_scanner: 139 | dependency: transitive 140 | description: 141 | name: string_scanner 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.0.4" 145 | term_glyph: 146 | dependency: transitive 147 | description: 148 | name: term_glyph 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "1.1.0" 152 | test_api: 153 | dependency: transitive 154 | description: 155 | name: test_api 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "0.2.4" 159 | typed_data: 160 | dependency: transitive 161 | description: 162 | name: typed_data 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "1.1.6" 166 | vector_math: 167 | dependency: transitive 168 | description: 169 | name: vector_math 170 | url: "https://pub.dartlang.org" 171 | source: hosted 172 | version: "2.0.8" 173 | sdks: 174 | dart: ">=2.2.0 <3.0.0" 175 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_vk_sdk_example 2 | description: Demonstrates how to use the flutter_vk_sdk plugin. 3 | publish_to: 'none' 4 | 5 | environment: 6 | sdk: ">=2.1.0 <3.0.0" 7 | 8 | dependencies: 9 | flutter: 10 | sdk: flutter 11 | 12 | # The following adds the Cupertino Icons font to your application. 13 | # Use with the CupertinoIcons class for iOS style icons. 14 | cupertino_icons: ^0.1.2 15 | camera_utils: ^0.1.8 16 | 17 | dev_dependencies: 18 | flutter_test: 19 | sdk: flutter 20 | 21 | flutter_vk_sdk: 22 | path: ../ 23 | 24 | # For information on the generic Dart part of this file, see the 25 | # following page: https://www.dartlang.org/tools/pub/pubspec 26 | 27 | # The following section is specific to Flutter. 28 | flutter: 29 | 30 | # The following line ensures that the Material Icons font is 31 | # included with your application, so that you can use the icons in 32 | # the material Icons class. 33 | uses-material-design: true 34 | 35 | # To add assets to your application, add an assets section, like this: 36 | # assets: 37 | # - images/a_dot_burr.jpeg 38 | # - images/a_dot_ham.jpeg 39 | 40 | # An image asset can refer to one or more resolution-specific "variants", see 41 | # https://flutter.dev/assets-and-images/#resolution-aware. 42 | 43 | # For details regarding adding assets from package dependencies, see 44 | # https://flutter.dev/assets-and-images/#from-packages 45 | 46 | # To add custom fonts to your application, add a fonts section here, 47 | # in this "flutter" section. Each entry in this list should have a 48 | # "family" key with the font family name, and a "fonts" key with a 49 | # list giving the asset and other descriptors for the font. For 50 | # example: 51 | # fonts: 52 | # - family: Schyler 53 | # fonts: 54 | # - asset: fonts/Schyler-Regular.ttf 55 | # - asset: fonts/Schyler-Italic.ttf 56 | # style: italic 57 | # - family: Trajan Pro 58 | # fonts: 59 | # - asset: fonts/TrajanPro.ttf 60 | # - asset: fonts/TrajanPro_Bold.ttf 61 | # weight: 700 62 | # 63 | # For details regarding fonts from package dependencies, 64 | # see https://flutter.dev/custom-fonts/#from-packages 65 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | //import 'package:flutter/material.dart'; 9 | //import 'package:flutter_test/flutter_test.dart'; 10 | 11 | //import 'package:flutter_vk_sdk_example/main.dart'; 12 | // 13 | //void main() { 14 | // testWidgets('Verify Platform version', (WidgetTester tester) async { 15 | // // Build our app and trigger a frame. 16 | // await tester.pumpWidget(MyApp()); 17 | // 18 | // // Verify that platform version is retrieved. 19 | // expect( 20 | // find.byWidgetPredicate( 21 | // (Widget widget) => widget is Text && widget.data.startsWith('Running on:'), 22 | // ), 23 | // findsOneWidget, 24 | // ); 25 | // }); 26 | //} 27 | -------------------------------------------------------------------------------- /flutter_vk_sdk.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyuqw/flutter_vk_sdk/571e517a9370b0e2ca3634b4feb64d7909256f95/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/Classes/FlutterVKSdkPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface FlutterVKSdkPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /ios/Classes/FlutterVKSdkPlugin.m: -------------------------------------------------------------------------------- 1 | #import "FlutterVKSdkPlugin.h" 2 | #import 3 | 4 | @implementation FlutterVKSdkPlugin 5 | + (void)registerWithRegistrar:(NSObject*)registrar { 6 | [SwiftFlutterVKSdkPlugin registerWithRegistrar:registrar]; 7 | } 8 | @end 9 | -------------------------------------------------------------------------------- /ios/Classes/SwiftFlutterVKSdkPlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import VK_ios_sdk 4 | 5 | enum VKAction: String { 6 | case initialize = "initialize" 7 | case login = "login" 8 | case logout = "logout" 9 | case getAccessToken = "get_access_token" 10 | case isLoggedIn = "is_logged_in" 11 | case share = "share" 12 | case apiCall = "api_method_call" 13 | case postCall = "post_method_call" 14 | } 15 | 16 | public class SwiftFlutterVKSdkPlugin: NSObject, FlutterPlugin { 17 | private let vkScope = [VK_PER_EMAIL, VK_PER_FRIENDS, VK_PER_OFFLINE, VK_PER_WALL] 18 | var methodChannelResult: FlutterResult! 19 | 20 | public static func register(with registrar: FlutterPluginRegistrar) { 21 | let channel = FlutterMethodChannel(name: "com.fb.fluttervksdk/vk", binaryMessenger: registrar.messenger()) 22 | let instance = SwiftFlutterVKSdkPlugin() 23 | registrar.addMethodCallDelegate(instance, channel: channel) 24 | } 25 | 26 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 27 | switch call.method { 28 | case VKAction.initialize.rawValue: 29 | guard let vkAppId: String = getArgument("app_id", from: call.arguments) else { 30 | result(FlutterError(code: "UNAVAILABLE", message: "VK login error", details: nil)) 31 | return 32 | } 33 | VKSdk.initialize(withAppId: vkAppId) 34 | VKSdk.instance().uiDelegate = self 35 | VKSdk.instance().register(self) 36 | result(["success": true]) 37 | break 38 | case VKAction.login.rawValue: 39 | loginVK(result, scope: getArgument("scope", from: call.arguments)) 40 | break 41 | case VKAction.share.rawValue: 42 | if VKSdk.isLoggedIn() { 43 | if let shareText: String = getArgument("text", from: call.arguments) { 44 | shareToVK(text: shareText, result: result) 45 | } else { 46 | result(FlutterError(code: "UNAVAILABLE", message: "VK share error", details: nil)) 47 | } 48 | } else { 49 | result(FlutterError(code: "UNAVAILABLE", message: "VK share error", details: nil)) 50 | } 51 | break 52 | case VKAction.logout.rawValue: 53 | VKSdk.forceLogout() 54 | result(["success": true]) 55 | break 56 | case VKAction.isLoggedIn.rawValue: 57 | result(VKSdk.isLoggedIn()) 58 | break 59 | case VKAction.postCall.rawValue: 60 | self.postMethodCall(arguments: call.arguments, result: result) 61 | break 62 | case VKAction.apiCall.rawValue: 63 | self.apiMethodCall(arguments: call.arguments, result: result) 64 | break 65 | default: 66 | return result(FlutterMethodNotImplemented) 67 | } 68 | } 69 | 70 | private func getArgument(_ name: String, from arguments: Any?) -> T? { 71 | guard let arguments = arguments as? [String: Any] else { return nil } 72 | return arguments[name] as? T 73 | } 74 | } 75 | 76 | class VKAPIRequest { 77 | var method: String 78 | var url: String? 79 | var parameters: [String: String] 80 | var retryCount: Int32? 81 | 82 | init(method: String, parameters: [String: String]?, retryCount: Int32? = 3) { 83 | self.method = method 84 | self.parameters = parameters ?? [:] 85 | self.retryCount = retryCount 86 | } 87 | 88 | // init(url: String, parameters: [String: String]?, retryCount: Int32? = 3) { 89 | // self.url = url 90 | // self.parameters = parameters ?? [:] 91 | // self.retryCount = retryCount 92 | // } 93 | 94 | func request(completeBlock: @escaping (_ vkResponse: VKResponse?) -> Void, errorBlock: @escaping (Error?) -> Void) { 95 | let newRequest: VKRequest = VKRequest(method: self.method, parameters: self.parameters) 96 | newRequest.parseModel = false 97 | newRequest.requestTimeout = 25 98 | if let attempts = retryCount { 99 | newRequest.attempts = attempts 100 | } 101 | newRequest.execute(resultBlock: completeBlock, errorBlock: errorBlock) 102 | } 103 | } 104 | 105 | extension SwiftFlutterVKSdkPlugin: VKSdkDelegate, VKSdkUIDelegate { 106 | func apiMethodCall(arguments: Any?, result: @escaping FlutterResult) { 107 | guard let methodName = getArgument("method", from: arguments) as String? else { 108 | return result(FlutterError(code: "VK API DELEGATE", message: "___________________ERROR: NO METHOD PASSED", details: nil)) 109 | } 110 | print("VK API DELEGATE", "___________________METHOD: \(methodName)") 111 | let args: Dictionary? = getArgument("arguments", from: arguments) 112 | let retryCount: Int32? = getArgument("retry_count", from: arguments) 113 | // var skipValidation: Bool? = getArgument("skip_validation", from: arguments) 114 | VKAPIRequest(method: methodName, parameters: args, retryCount: retryCount).request( 115 | completeBlock: { vkResult in 116 | print("VK API DELEGATE", "___________________SUCCESS: \(vkResult?.responseString)") 117 | result(vkResult?.responseString ?? "") 118 | }, 119 | errorBlock: { error in 120 | // TODO : common error handler 121 | print("VK API DELEGATE", "___________________ERROR: \(error.debugDescription)") 122 | result(FlutterError(code: "\(methodName)_ERROR", message: error.debugDescription, details: nil)) 123 | } 124 | ) 125 | } 126 | func postMethodCall(arguments: Any?, result: @escaping FlutterResult) { 127 | guard let url = getArgument("url", from: arguments) as String? else { 128 | return print("VK API DELEGATE", "___________________NO URL PASSED") 129 | } 130 | print("VK API DELEGATE", "___________________POST URL: \(url)") 131 | 132 | let args: Dictionary? = getArgument("arguments", from: arguments) 133 | 134 | guard let photo = args?["photo"] else { 135 | return result(FlutterError(code: "VK API DELEGATE", message: "___________________ERROR: NO PHOTO PASSED", details: nil)) 136 | } 137 | 138 | let _image = VKUploadImage(data: try? Data(contentsOf: URL(string: photo)!), andParams: VKImageParameters.pngImage()) 139 | VKRequest.photoRequest(withPostUrl: url, withPhotos: [_image]).execute( 140 | resultBlock: { vkResult in 141 | print("VK API DELEGATE", "___________________SUCCESS: \(vkResult?.responseString)") 142 | result(vkResult?.responseString ?? "") 143 | }, 144 | errorBlock: { error in 145 | // TODO : common error handler 146 | print("VK API DELEGATE", "___________________ERROR: \(error.debugDescription)") 147 | result(FlutterError(code: "POST_ERROR", message: error.debugDescription, details: nil)) 148 | } 149 | ) 150 | } 151 | 152 | func getImgPath(name: String) -> UIImage? 153 | { 154 | let documentDirectory = FileManager.SearchPathDirectory.documentDirectory 155 | let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask 156 | let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true) 157 | if let dirPath = paths.first 158 | { 159 | let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(name) 160 | let image = UIImage(contentsOfFile: imageURL.path) 161 | return image 162 | } 163 | return nil 164 | } 165 | 166 | func loginVK(_ result: @escaping FlutterResult, scope: String?) { 167 | self.methodChannelResult = result 168 | let _scope = scopesFromString(scope) 169 | VKSdk.wakeUpSession(_scope) { state, error in 170 | switch state { 171 | case .authorized: 172 | if let token = VKSdk.accessToken() { 173 | self.authorizeVK(with: token) 174 | } else { 175 | result(FlutterError(code: "UNAVAILABLE", message: "VK login error", details: nil)) 176 | } 177 | break 178 | case .initialized: 179 | VKSdk.authorize(_scope) 180 | break 181 | case .error: 182 | result(FlutterError(code: "UNAVAILABLE", message: "VK login error", details: nil)) 183 | break 184 | default: 185 | break 186 | } 187 | } 188 | } 189 | 190 | func scopesFromString(_ scopesStr: String?) -> [String] { 191 | guard let _scopesStr = scopesStr else {return self.vkScope} 192 | let arr = _scopesStr.components(separatedBy: ",") 193 | return arr.map({$0.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()}) 194 | } 195 | 196 | func authorizeVK(with token: VKAccessToken) { 197 | let data: [String: Any?] = [ 198 | "token": token.accessToken, 199 | "userId": Int(token.userId), 200 | "expiresIn": token.expiresIn, 201 | "secret": token.secret, 202 | "email": token.email 203 | ] 204 | methodChannelResult(data) 205 | } 206 | 207 | func shareToVK(text: String, result: @escaping FlutterResult) { 208 | guard 209 | let rootController = UIApplication.shared.keyWindow?.rootViewController else { 210 | // TODO: Should dispatch error 211 | return 212 | } 213 | 214 | let shareDialog = VKShareDialogController() 215 | shareDialog.text = text 216 | // let image = Constants.postcardImages[self.postcard.id] 217 | // if image != "" { 218 | // shareDialog.vkImages = [image] 219 | // } 220 | // shareDialog.shareLink = VKShareLink(title: "Выиграй поездку для своих близких в Тюмень!", link: URL(string: "https://visit-tyumen.ru/postcards")) 221 | 222 | shareDialog.completionHandler = { controller, _result in 223 | switch _result { 224 | case VKShareDialogControllerResult.cancelled: 225 | result(FlutterError(code: "UNAVAILABLE", message: "VK share error", details: nil)) 226 | case VKShareDialogControllerResult.done: 227 | result(controller?.postId) 228 | default: 229 | result(FlutterError(code: "UNAVAILABLE", message: "VK share error", details: nil)) 230 | } 231 | rootController.dismiss(animated: true) 232 | } 233 | 234 | rootController.present(shareDialog, animated: true, completion: nil) 235 | } 236 | public func vkSdkAccessAuthorizationFinished(with result: VKAuthorizationResult!) { 237 | if result.token != nil { 238 | self.authorizeVK(with: result.token) 239 | } else { 240 | self.methodChannelResult(FlutterError(code: "UNAVAILABLE", message: "VK login error", details: nil)) 241 | } 242 | } 243 | 244 | public func vkSdkUserAuthorizationFailed() { 245 | 246 | } 247 | 248 | public func vkSdkShouldPresent(_ controller: UIViewController!) { 249 | // dispatch(.vkSdkShouldPresent) 250 | guard let rootController = UIApplication.shared.keyWindow?.rootViewController else { 251 | // TODO: Should dispatch error 252 | return 253 | } 254 | rootController.present(controller, animated: true) 255 | } 256 | 257 | public func vkSdkNeedCaptchaEnter(_ captchaError: VKError!) { 258 | // dispatch(.vkSdkNeedCaptchaEnter, payload: [ 259 | // "error": captchaError.errorMessage, 260 | // ]) 261 | 262 | guard 263 | let rootController = UIApplication.shared.keyWindow?.rootViewController, 264 | let controller = VKCaptchaViewController.captchaControllerWithError(captchaError) else { 265 | return 266 | } 267 | 268 | rootController.present(controller, animated: true) 269 | } 270 | 271 | } 272 | 273 | -------------------------------------------------------------------------------- /ios/flutter_vk_sdk.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'flutter_vk_sdk' 6 | s.version = '0.0.1' 7 | s.summary = 'Flutter vk sdk project.' 8 | s.description = <<-DESC 9 | Flutter vk sdk project. 10 | DESC 11 | s.homepage = 'http://example.com' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Your Company' => 'email@example.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | s.dependency 'VK-ios-sdk' 19 | 20 | s.ios.deployment_target = '8.0' 21 | end 22 | 23 | -------------------------------------------------------------------------------- /lib/flutter_vk_sdk.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | import 'package:flutter/services.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | import 'models/attachment.dart'; 7 | import 'models/vk_access_token.dart'; 8 | import 'ui/vk_share_page.dart'; 9 | import 'vk_api/vk_api.dart'; 10 | 11 | class FlutterVKSdk { 12 | static final String _defaultScope = null; 13 | static const MethodChannel channel = const MethodChannel('com.fb.fluttervksdk/vk'); 14 | static final api = VKApi(); 15 | 16 | static Map _cast(Map items) { 17 | return items?.cast(); 18 | } 19 | 20 | static Future init({String appId, String apiVersion}) async { 21 | if (Platform.isIOS) { 22 | // TODO apiVersion for iOS 23 | final Map init = await channel.invokeMethod('initialize', {'app_id': appId, 'api_verson': apiVersion}); 24 | return init; 25 | } 26 | return null; 27 | } 28 | 29 | static Future isLoggedIn() async { 30 | return await channel.invokeMethod('is_logged_in'); 31 | } 32 | 33 | static Future getAccessToken() async { 34 | final Map token = await channel.invokeMethod('get_access_token'); 35 | return VKAccessToken.fromJson(_cast(token)); 36 | } 37 | 38 | static Future login({ 39 | String scope, 40 | @required Function(VKAccessToken) onSuccess, 41 | @required Function(PlatformException) onError, 42 | }) async { 43 | assert(onSuccess != null); 44 | assert(onError != null); 45 | try { 46 | if (scope == null || scope.isEmpty) scope = _defaultScope; 47 | final Map login = await channel.invokeMethod('login', {'scope': scope}); 48 | onSuccess(VKAccessToken.fromJson(_cast(login))); 49 | } on PlatformException catch (e) { 50 | onError(e); 51 | } 52 | } 53 | 54 | static Future logout() async { 55 | return channel.invokeMethod('logout'); 56 | } 57 | 58 | static shareWithDialog({ 59 | @required BuildContext context, 60 | @required Function(String) onSuccess, 61 | @required Function(PlatformException) onError, 62 | String text, 63 | List attachments, 64 | Future Function(AttachmentType) addAttachments, 65 | }) { 66 | assert(onSuccess != null); 67 | assert(onError != null); 68 | return VKSharePage.show( 69 | context: context, 70 | onSuccess: onSuccess, 71 | onError: onError, 72 | text: text, 73 | attachments: attachments, 74 | addAttachmentsDelegate: addAttachments, 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/models/attachment.dart: -------------------------------------------------------------------------------- 1 | enum AttachmentType { photo, video, url } 2 | 3 | class Attachment { 4 | final AttachmentType type; 5 | final String value; 6 | final String thumbnail; 7 | 8 | Attachment(this.type, this.value, {this.thumbnail}) 9 | : assert(type != null), 10 | assert(value != null); 11 | 12 | @override 13 | bool operator ==(other) { 14 | return other is Attachment && type == other.type && value == other.value; 15 | } 16 | 17 | @override 18 | int get hashCode => type.hashCode + value.hashCode; 19 | } 20 | -------------------------------------------------------------------------------- /lib/models/vk_access_token.dart: -------------------------------------------------------------------------------- 1 | class VKAccessToken { 2 | final int userId; 3 | final String token; 4 | final String secret; 5 | final String email; 6 | final String phone; 7 | final String phoneAccessKey; 8 | 9 | VKAccessToken(this.userId, this.token, this.secret, this.email, this.phone, this.phoneAccessKey); 10 | 11 | VKAccessToken.fromJson(Map json) 12 | : assert(json != null), 13 | userId = json['userId'], 14 | token = json['token'], 15 | secret = json['secret'], 16 | email = json['email'], 17 | phone = json['phone'], 18 | phoneAccessKey = json['phoneAccessKey']; 19 | } 20 | -------------------------------------------------------------------------------- /lib/ui/vk_share_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:math'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_vk_sdk/utils/share_utils.dart'; 6 | 7 | import '../models/attachment.dart'; 8 | import 'vk_theme.dart'; 9 | 10 | enum UITheme { vk, app } 11 | 12 | class VKSharePage extends StatefulWidget { 13 | final Function onSuccess; 14 | final Function onError; 15 | final String text; 16 | final List attachments; 17 | final Future Function(AttachmentType) addAttachmentsDelegate; 18 | final UITheme theme; 19 | 20 | const VKSharePage({ 21 | Key key, 22 | this.onSuccess, 23 | this.onError, 24 | this.text, 25 | this.attachments, 26 | this.addAttachmentsDelegate, 27 | this.theme = UITheme.vk, 28 | }) : assert(onSuccess != null), 29 | assert(onError != null), 30 | assert(theme != null), 31 | super(key: key); 32 | 33 | @override 34 | VKSharePageState createState() => VKSharePageState(); 35 | 36 | static Future show({ 37 | @required BuildContext context, 38 | @required Function onSuccess, 39 | @required Function onError, 40 | String text, 41 | List attachments, 42 | Future Function(AttachmentType) addAttachmentsDelegate, 43 | theme = UITheme.vk, 44 | }) { 45 | return Navigator.push( 46 | context, 47 | MaterialPageRoute( 48 | builder: (c) => VKSharePage( 49 | onSuccess: onSuccess, 50 | onError: onError, 51 | text: text, 52 | attachments: attachments, 53 | addAttachmentsDelegate: addAttachmentsDelegate, 54 | theme: theme, 55 | ), 56 | ), 57 | ); 58 | } 59 | } 60 | 61 | class VKSharePageState extends State { 62 | bool isLoading = false; 63 | TextEditingController textCtrl; 64 | List attachments; 65 | 66 | @override 67 | void initState() { 68 | super.initState(); 69 | textCtrl = TextEditingController(text: widget.text); 70 | attachments = widget.attachments ?? []; 71 | } 72 | 73 | @override 74 | void dispose() { 75 | textCtrl.dispose(); 76 | super.dispose(); 77 | } 78 | 79 | @override 80 | Widget build(BuildContext context) { 81 | final child = Scaffold( 82 | appBar: buildAppBar(context), 83 | body: buildBody(context), 84 | ); 85 | 86 | if (widget.theme == UITheme.vk) return buildVKTheme(context, child); 87 | return child; 88 | } 89 | 90 | Widget buildVKTheme(BuildContext context, Widget child) { 91 | final themeData = VKTheme.getTheme(context); 92 | return Theme(data: themeData, child: child); 93 | } 94 | 95 | Widget buildAppBar(BuildContext context) { 96 | // final theme = Theme.of(context).iconTheme; 97 | final iconColor = null; 98 | return AppBar( 99 | leading: CustomIconButton( 100 | child: Icon(Icons.arrow_back, color: iconColor), 101 | onTap: handleBackButtonTap, 102 | tooltip: MaterialLocalizations.of(context).backButtonTooltip, 103 | ), 104 | actions: [ 105 | AspectRatio( 106 | aspectRatio: 1.0, 107 | child: CustomIconButton(child: Icon(Icons.check, color: iconColor), onTap: handleDoneButtonTap), 108 | ), 109 | ], 110 | ); 111 | } 112 | 113 | Widget buildBody(BuildContext context) { 114 | final List children = [ 115 | Layout( 116 | child: buildContent(context), 117 | bottom: buildBottomBar(context), 118 | ) 119 | ]; 120 | if (isLoading) children.add(buildLoaderIndicator(context)); 121 | return Stack(children: children); 122 | } 123 | 124 | Widget buildLoaderIndicator(BuildContext context) { 125 | return AbsorbPointer(child: Center(child: CircularProgressIndicator())); 126 | } 127 | 128 | Widget buildContent(BuildContext context) { 129 | return ListView( 130 | padding: EdgeInsets.symmetric(horizontal: 12.0), 131 | children: [ 132 | buildTextInput(context), 133 | buildAttachments(context), 134 | ], 135 | ); 136 | } 137 | 138 | Widget buildTextInput(BuildContext context) { 139 | return TextField( 140 | minLines: 1, 141 | maxLines: 20, 142 | controller: textCtrl, 143 | decoration: InputDecoration( 144 | border: InputBorder.none, 145 | ), 146 | ); 147 | } 148 | 149 | Widget buildAttachments(BuildContext context) { 150 | return AttachmentsWidget( 151 | onRemove: handleOnRemoveAttachment, 152 | attachments: attachments, 153 | ); 154 | } 155 | 156 | Widget buildBottomBar(BuildContext context) { 157 | final theme = Theme.of(context); 158 | final List children = []; 159 | final imageBtn = buildAddImageButton(context); 160 | if (imageBtn != null) children.add(imageBtn); 161 | final videoBtn = buildAddVideoButton(context); 162 | if (videoBtn != null) children.add(videoBtn); 163 | if (children.length == 0) return null; 164 | return BottomAppBar( 165 | child: Container( 166 | height: kBottomNavigationBarHeight, 167 | color: theme.bottomAppBarColor, 168 | child: Row(crossAxisAlignment: CrossAxisAlignment.stretch, children: children), 169 | ), 170 | ); 171 | } 172 | 173 | Widget buildAddImageButton(BuildContext context) { 174 | if (widget.addAttachmentsDelegate == null) return null; 175 | return AspectRatio(aspectRatio: 1, child: CustomIconButton(child: Icon(Icons.image), onTap: handleAddImageTap)); 176 | } 177 | 178 | Widget buildAddVideoButton(BuildContext context) { 179 | if (widget.addAttachmentsDelegate == null) return null; 180 | return AspectRatio( 181 | aspectRatio: 1, 182 | child: CustomIconButton(child: Icon(Icons.video_library), onTap: handleAddVideoTap), 183 | ); 184 | } 185 | 186 | handleBackButtonTap() { 187 | navigateBack(); 188 | } 189 | 190 | handleDoneButtonTap() { 191 | share(); 192 | } 193 | 194 | navigateBack() { 195 | Navigator.pop(context); 196 | } 197 | 198 | handleAddImageTap() { 199 | addAttachments(AttachmentType.photo); 200 | } 201 | 202 | handleAddVideoTap() { 203 | addAttachments(AttachmentType.video); 204 | } 205 | 206 | addAttachments(AttachmentType type) async { 207 | if (widget.addAttachmentsDelegate == null || isLoading) return; 208 | final items = await widget.addAttachmentsDelegate(type); 209 | if (items == null) return; 210 | items.forEach((attachment) { 211 | if (!attachments.contains(attachment)) attachments.add(attachment); 212 | }); 213 | setState(() {}); 214 | } 215 | 216 | handleOnRemoveAttachment(Attachment attachment) { 217 | if (attachment == null) return; 218 | attachments.remove(attachment); 219 | setState(() {}); 220 | } 221 | 222 | setLoading(bool value) { 223 | if (isLoading == value) return; 224 | setState(() { 225 | isLoading = value; 226 | }); 227 | } 228 | 229 | share() { 230 | if (isLoading) return; 231 | setLoading(true); 232 | final text = textCtrl.text; 233 | Share(message: text, attachments: attachments).execute( 234 | onSuccess: handleShareSuccess, 235 | onError: handleShareError, 236 | ); 237 | } 238 | 239 | handleShareSuccess(postId) { 240 | setLoading(false); 241 | widget.onSuccess(postId); 242 | navigateBack(); 243 | } 244 | 245 | handleShareError(error) { 246 | setLoading(false); 247 | widget.onError(error); 248 | } 249 | } 250 | 251 | class CustomIconButton extends StatelessWidget { 252 | final Widget child; 253 | final String tooltip; 254 | final Function() onTap; 255 | final Color color; 256 | 257 | const CustomIconButton({Key key, this.child, @required this.onTap, this.tooltip, this.color}) : super(key: key); 258 | 259 | @override 260 | Widget build(BuildContext context) { 261 | var content = child; 262 | if (tooltip?.isNotEmpty == true) content = Tooltip(message: tooltip, child: content); 263 | return Container( 264 | padding: EdgeInsets.all(4.0), 265 | child: Material( 266 | type: color == null ? MaterialType.transparency : MaterialType.canvas, 267 | shape: CircleBorder(), 268 | color: color, 269 | clipBehavior: Clip.hardEdge, 270 | child: InkWell(onTap: onTap, child: content), 271 | ), 272 | ); 273 | } 274 | } 275 | 276 | class Layout extends StatelessWidget { 277 | final Widget top; 278 | final Widget child; 279 | final Widget bottom; 280 | 281 | const Layout({Key key, this.top, this.bottom, this.child}) 282 | : assert(child != null), 283 | super(key: key); 284 | 285 | @override 286 | Widget build(BuildContext context) { 287 | final List children = []; 288 | if (top != null) children.add(top); 289 | children.add(Expanded(child: child)); 290 | if (bottom != null) children.add(bottom); 291 | return Column( 292 | crossAxisAlignment: CrossAxisAlignment.stretch, 293 | children: children, 294 | ); 295 | } 296 | } 297 | 298 | class AttachmentsWidget extends StatelessWidget { 299 | final List attachments; 300 | final Function(Attachment) onRemove; 301 | 302 | const AttachmentsWidget({Key key, this.attachments, this.onRemove}) : super(key: key); 303 | 304 | @override 305 | Widget build(BuildContext context) { 306 | if (attachments == null) return Container(); 307 | 308 | final List children = []; 309 | final List urls = []; 310 | attachments.forEach((a) { 311 | final child = AttachmentPreview(item: a, onRemove: onRemove, perRow: min(attachments.length, 4)); 312 | if (a.type == AttachmentType.url) 313 | urls.add(child); 314 | else 315 | children.add(child); 316 | }); 317 | children.addAll(urls); 318 | return Wrap( 319 | alignment: WrapAlignment.spaceBetween, 320 | crossAxisAlignment: WrapCrossAlignment.center, 321 | children: children, 322 | ); 323 | } 324 | } 325 | 326 | class AttachmentPreview extends StatelessWidget { 327 | final Attachment item; 328 | final int perRow; 329 | final Function(Attachment) onRemove; 330 | 331 | const AttachmentPreview({Key key, this.item, this.perRow = 1, this.onRemove}) : super(key: key); 332 | 333 | @override 334 | Widget build(BuildContext context) { 335 | Widget child; 336 | switch (item.type) { 337 | case AttachmentType.url: 338 | child = buildUrl(context); 339 | return buildItemCard(context, child); 340 | case AttachmentType.photo: 341 | child = buildPhoto(context); 342 | break; 343 | case AttachmentType.video: 344 | child = buildVideo(context); 345 | break; 346 | default: 347 | break; 348 | } 349 | return buildItemLayout(context, buildItemCard(context, child)); 350 | } 351 | 352 | Widget buildItemCard(BuildContext context, Widget child) { 353 | return Card( 354 | clipBehavior: Clip.hardEdge, 355 | child: child == null 356 | ? null 357 | : Stack( 358 | children: [ 359 | child, 360 | Positioned(right: 0.0, child: buildRemoveButton(context)), 361 | ], 362 | ), 363 | ); 364 | } 365 | 366 | Widget buildItemLayout(BuildContext context, Widget child) { 367 | return LayoutBuilder( 368 | builder: (BuildContext c, BoxConstraints constraints) { 369 | final screenWidth = MediaQuery.of(context).size.width; 370 | final size = getMediaWidth(context, min(constraints.maxWidth, screenWidth), perRow); 371 | final minSize = 80.0; 372 | return Container( 373 | constraints: BoxConstraints(minWidth: minSize, maxWidth: size, minHeight: minSize, maxHeight: size), 374 | child: Center(child: child), 375 | ); 376 | }, 377 | ); 378 | } 379 | 380 | Widget buildRemoveButton(BuildContext context) { 381 | if (onRemove == null) return Container(); 382 | final theme = Theme.of(context); 383 | final size = 18.0; 384 | return CustomIconButton( 385 | onTap: handleOnRemoveTap, 386 | color: theme.canvasColor, 387 | child: Icon(Icons.close, size: size), 388 | ); 389 | } 390 | 391 | Widget buildUrl(BuildContext context) { 392 | final padding = 4.0; 393 | return Container( 394 | padding: EdgeInsets.only(left: padding, top: padding, right: 20.0, bottom: padding), 395 | child: Text(item.value), 396 | ); 397 | } 398 | 399 | Widget buildPhoto(BuildContext context) { 400 | final path = item.thumbnail ?? item.value; 401 | return Image.asset(path, fit: BoxFit.cover); 402 | } 403 | 404 | Widget buildVideo(BuildContext context) { 405 | final minSize = 80.0; 406 | final child = item.thumbnail == null 407 | ? Icon(Icons.video_library, size: minSize * 0.5) 408 | : Image.asset(item.thumbnail, fit: BoxFit.cover); 409 | return child; 410 | } 411 | 412 | double getMediaWidth(BuildContext context, double maxWidth, int countPerRow) { 413 | assert(countPerRow > 0); 414 | 415 | final theme = Theme.of(context).cardTheme; 416 | final margin = theme.margin?.horizontal ?? 4.0; 417 | var width = maxWidth; 418 | width = (width - margin * countPerRow) / countPerRow; 419 | // width = min(width, 180.0); 420 | return width; 421 | } 422 | 423 | handleOnRemoveTap() { 424 | if (onRemove == null) return; 425 | onRemove(item); 426 | } 427 | } 428 | -------------------------------------------------------------------------------- /lib/ui/vk_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class VKTheme { 4 | static final colors = _C(); 5 | 6 | static ThemeData getTheme(BuildContext context) { 7 | return ThemeData( 8 | primaryColor: Colors.white, 9 | appBarTheme: AppBarTheme(elevation: 1.0), 10 | canvasColor: Colors.white, 11 | primaryIconTheme: IconThemeData(color: Colors.grey), 12 | iconTheme: IconThemeData(color: Colors.grey), 13 | ); 14 | } 15 | } 16 | 17 | class _C {} 18 | -------------------------------------------------------------------------------- /lib/utils/share_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/services.dart'; 3 | 4 | import '../flutter_vk_sdk.dart'; 5 | import '../vk_method_call.dart'; 6 | import '../models/attachment.dart'; 7 | 8 | String getFileUri(String source) { 9 | if (source == null || source.toLowerCase().startsWith('file:///')) return source; 10 | return Uri.file(source).toString(); 11 | } 12 | 13 | class Share { 14 | var wallUploadServer; 15 | 16 | int ownerId; 17 | String message; 18 | List attachments; 19 | bool fromGroup; 20 | bool friendsOnly; 21 | bool closeComments; 22 | bool muteNotifications; 23 | 24 | Share({ 25 | this.ownerId, 26 | this.message, 27 | this.attachments, 28 | this.fromGroup, 29 | this.friendsOnly, 30 | this.closeComments, 31 | this.muteNotifications, 32 | }); 33 | 34 | execute({ 35 | @required Function onSuccess, 36 | @required Function onError, 37 | }) async { 38 | try { 39 | String attachmentsStr = await getAttachments(attachments); 40 | 41 | FlutterVKSdk.api.wall 42 | .post( 43 | ownerId: ownerId, 44 | message: message, 45 | attachments: attachmentsStr, 46 | fromGroup: fromGroup, 47 | friendsOnly: friendsOnly, 48 | closeComments: closeComments, 49 | muteNotifications: muteNotifications, 50 | ) 51 | .execute(onSuccess: onSuccess, onError: onError); 52 | } on PlatformException catch (e) { 53 | onError(e); 54 | } catch (e) { 55 | onError(e); 56 | } 57 | } 58 | 59 | getWallUploadServer() async { 60 | if (wallUploadServer == null) { 61 | wallUploadServer = FlutterVKSdk.api.photos.getWallUploadServer().executeSync(); 62 | } 63 | assert(wallUploadServer != null); 64 | return wallUploadServer; 65 | } 66 | 67 | Future getAttachments(List attachments) async { 68 | if (attachments == null || attachments.isEmpty) return null; 69 | List attachmentsStr = []; 70 | for (var i = 0; i < attachments.length; i++) { 71 | final a = attachments[i]; 72 | String value; 73 | switch (a.type) { 74 | case AttachmentType.photo: 75 | value = await uploadPhoto(a.value); 76 | break; 77 | case AttachmentType.video: 78 | value = await uploadVideo(a.value); 79 | break; 80 | case AttachmentType.url: 81 | value = a.value; 82 | break; 83 | default: 84 | break; 85 | } 86 | if (value?.isNotEmpty == true) attachmentsStr.add(value); 87 | } 88 | if (attachmentsStr.isEmpty) return null; 89 | return attachmentsStr.join(','); 90 | } 91 | 92 | Future uploadPhoto(String source) async { 93 | final uploadServer = await getWallUploadServer(); 94 | final saveInfo = await PhotoUploader(wallUploadServer: uploadServer).uploadWallPhoto(source); 95 | final ownerId = saveInfo['owner_id']; 96 | final id = saveInfo['id']; 97 | return 'photo${ownerId}_$id'; 98 | } 99 | 100 | Future uploadVideo(String source) async { 101 | final saveInfo = await VideoUploader().uploadVideo(source); 102 | final ownerId = saveInfo['owner_id']; 103 | final videoId = saveInfo['video_id']; 104 | return 'video${ownerId}_$videoId'; 105 | } 106 | } 107 | 108 | class PhotoUploader { 109 | var _wallUploadServer; 110 | 111 | PhotoUploader({wallUploadServer}) : _wallUploadServer = wallUploadServer; 112 | 113 | getWallUploadServer() async { 114 | if (_wallUploadServer == null) { 115 | _wallUploadServer = FlutterVKSdk.api.photos.getWallUploadServer().executeSync(); 116 | } 117 | assert(_wallUploadServer != null); 118 | return _wallUploadServer; 119 | } 120 | 121 | Future uploadWallPhoto(String source) async { 122 | final uploadServer = await getWallUploadServer(); 123 | final uploadBuilder = VKPostMethodCall(uploadServer['upload_url']); 124 | uploadBuilder.setValue('photo', getFileUri(source)); 125 | var fileInfo = await uploadBuilder.executeSync(); 126 | if (fileInfo is List) fileInfo = fileInfo[0]; 127 | var saveInfo = await FlutterVKSdk.api.photos 128 | .saveWallPhoto(server: fileInfo['server'], photo: fileInfo['photo'], hash: fileInfo['hash']) 129 | .executeSync(); 130 | if (saveInfo is List) saveInfo = saveInfo[0]; 131 | return saveInfo; 132 | } 133 | } 134 | 135 | class VideoUploader { 136 | var _uploadServer; 137 | 138 | VideoUploader({uploadServer}) : _uploadServer = uploadServer; 139 | 140 | getUploadServer() async { 141 | if (_uploadServer == null) { 142 | _uploadServer = FlutterVKSdk.api.video.save().executeSync(); 143 | } 144 | assert(_uploadServer != null); 145 | return _uploadServer; 146 | } 147 | 148 | Future uploadVideo(String source) async { 149 | final uploadServer = await getUploadServer(); 150 | final uploadBuilder = VKPostMethodCall(uploadServer['upload_url']); 151 | uploadBuilder.setValue('video_file', getFileUri(source)); 152 | var fileInfo = await uploadBuilder.executeSync(); 153 | if (fileInfo is List) fileInfo = fileInfo[0]; 154 | return fileInfo; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /lib/vk_api/photos.dart: -------------------------------------------------------------------------------- 1 | import '../vk_method_call.dart'; 2 | 3 | class Photos { 4 | VKApiMethodCall getWallUploadServer({int groupId}) { 5 | final callBuilder = VKApiMethodCall('photos.getWallUploadServer'); 6 | callBuilder.setValue('group_id', groupId); 7 | return callBuilder; 8 | } 9 | 10 | VKApiMethodCall saveWallPhoto({ 11 | int userId, 12 | int groupId, 13 | String photo, 14 | int server, 15 | String hash, 16 | double latitude, 17 | double longitude, 18 | String caption, 19 | }) { 20 | final callBuilder = VKApiMethodCall('photos.saveWallPhoto'); 21 | callBuilder.setValue('user_id', groupId); 22 | callBuilder.setValue('group_id', groupId); 23 | callBuilder.setValue('photo', photo); 24 | callBuilder.setValue('server', server); 25 | callBuilder.setValue('hash', hash); 26 | callBuilder.setValue('latitude', latitude); 27 | callBuilder.setValue('longitude', longitude); 28 | callBuilder.setValue('caption', caption); 29 | return callBuilder; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/vk_api/video.dart: -------------------------------------------------------------------------------- 1 | import '../vk_method_call.dart'; 2 | 3 | class Video { 4 | VKApiMethodCall save({ 5 | String name, 6 | String description, 7 | bool isPrivate, 8 | bool wallpost, 9 | String link, 10 | int groupId, 11 | int albumId, 12 | String privacyView, 13 | String privacyComment, 14 | bool noComments, 15 | bool repeat, 16 | bool compression, 17 | }) { 18 | final callBuilder = VKApiMethodCall('video.save'); 19 | callBuilder.setValue('name', name); 20 | callBuilder.setValue('description', description); 21 | callBuilder.setBool('is_private', isPrivate); 22 | callBuilder.setBool('wallpost', wallpost); 23 | callBuilder.setValue('link', link); 24 | callBuilder.setValue('group_id', groupId); 25 | callBuilder.setValue('album_id', albumId); 26 | callBuilder.setValue('privacy_view', privacyView); 27 | callBuilder.setValue('privacy_comment', privacyComment); 28 | callBuilder.setBool('no_comments', noComments); 29 | callBuilder.setBool('repeat', repeat); 30 | callBuilder.setBool('compression', compression); 31 | return callBuilder; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/vk_api/vk_api.dart: -------------------------------------------------------------------------------- 1 | import '../vk_method_call.dart'; 2 | import 'photos.dart'; 3 | import 'video.dart'; 4 | import 'wall.dart'; 5 | 6 | class VKApi { 7 | VKApiMethodCall createMethodCall(String method) { 8 | assert(method?.isNotEmpty == true); 9 | return VKApiMethodCall(method); 10 | } 11 | 12 | final photos = Photos(); 13 | final video = Video(); 14 | final wall = Wall(); 15 | } 16 | -------------------------------------------------------------------------------- /lib/vk_api/wall.dart: -------------------------------------------------------------------------------- 1 | import '../vk_method_call.dart'; 2 | 3 | class Wall { 4 | VKApiMethodCall post({ 5 | int ownerId, 6 | String message, 7 | String attachments, 8 | bool fromGroup, 9 | bool friendsOnly, 10 | bool closeComments, 11 | bool muteNotifications, 12 | }) { 13 | final callBuilder = VKApiMethodCall('wall.post'); 14 | callBuilder.setValue('owner_id', ownerId); 15 | callBuilder.setValue('message', message); 16 | callBuilder.setValue('attachments', attachments); 17 | callBuilder.setBool('friends_only', friendsOnly); 18 | callBuilder.setBool('from_group', fromGroup); 19 | callBuilder.setBool('close_comments', closeComments); 20 | callBuilder.setBool('mute_notifications', muteNotifications); 21 | return callBuilder; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/vk_method_call.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | import 'dart:convert' show utf8; 3 | 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:flutter/services.dart'; 6 | import 'package:http/http.dart' as http; 7 | 8 | import 'flutter_vk_sdk.dart'; 9 | import 'vk_response_parser.dart'; 10 | 11 | class VKMethodCall { 12 | String _channelMethod; 13 | final String endpoint; 14 | Map _args = {}; 15 | VKResponseParser parser; 16 | 17 | VKMethodCall(this.endpoint); 18 | 19 | MethodChannel get channel => FlutterVKSdk.channel; 20 | 21 | UnmodifiableMapView get args => UnmodifiableMapView(_args); 22 | 23 | set args(Map values) { 24 | if (values == null) return; 25 | final items = Map(); 26 | values.forEach((k, v) { 27 | if (!isEmptyKey(k) && !isEmptyKey(v)) items[k] = v; 28 | }); 29 | _args.addAll(items); 30 | } 31 | 32 | setValue(String key, dynamic value) { 33 | final val = value is String ? value : value?.toString(); 34 | if (isEmptyKey(key) || isEmptyValue(val)) return; 35 | _args[key] = val; 36 | } 37 | 38 | setBool(String key, bool value) { 39 | if (isEmptyValue(key) || value == null) return; 40 | _args[key] = (value ? 1 : 0).toString(); 41 | } 42 | 43 | bool isEmptyKey(String value) { 44 | return value?.isNotEmpty != true; 45 | } 46 | 47 | bool isEmptyValue(String value) { 48 | return value?.isNotEmpty != true; 49 | } 50 | 51 | String getEndpoint() { 52 | assert(endpoint?.isNotEmpty == true); 53 | return endpoint; 54 | } 55 | 56 | String getChannelMethod() { 57 | assert(_channelMethod?.isNotEmpty == true); 58 | return _channelMethod; 59 | } 60 | 61 | Map getChannelArguments() { 62 | return _args; 63 | } 64 | 65 | dynamic parse(response, VKResponseParser parser) { 66 | final p = parser ?? this.parser; 67 | if (p == null) return response; 68 | return p.parse(response); 69 | } 70 | 71 | Future callMethod([dynamic arguments]) { 72 | return channel.invokeMethod(getChannelMethod(), arguments); 73 | } 74 | 75 | Future executeSync({VKResponseParser parser}) async { 76 | // TODO catch errors 77 | final response = await callMethod(getChannelArguments()); 78 | return parse(response, parser); 79 | } 80 | 81 | execute({@required Function onSuccess, @required Function onError, VKResponseParser parser}) async { 82 | assert(onSuccess != null); 83 | assert(onError != null); 84 | try { 85 | final res = await executeSync(parser: parser); 86 | onSuccess(res); 87 | } on PlatformException catch (e) { 88 | onError(e); 89 | } 90 | } 91 | } 92 | 93 | class VKApiMethodCall extends VKMethodCall { 94 | final _methodStr = 'method'; 95 | final _argumentsStr = 'arguments'; 96 | final _retryCountStr = 'retry_count'; 97 | final _skipValidationStr = 'skip_validation'; 98 | String _channelMethod = 'api_method_call'; 99 | int retryCount = 3; 100 | bool skipValidation; 101 | VKResponseParser parser = VKApiResponseParser(); 102 | 103 | VKApiMethodCall(String method) : super(method); 104 | 105 | @override 106 | Map getChannelArguments() { 107 | final Map res = {_methodStr: getEndpoint()}; 108 | if (_args?.isNotEmpty == true) res[_argumentsStr] = _args; 109 | if (retryCount != null) res[_retryCountStr] = retryCount; 110 | if (skipValidation != null) res[_skipValidationStr] = skipValidation; 111 | return res; 112 | } 113 | } 114 | 115 | class VKPostMethodCall extends VKMethodCall { 116 | final _urlStr = 'url'; 117 | final _argumentsStr = 'arguments'; 118 | final _retryCountStr = 'retry_count'; 119 | final _timeoutStr = 'timeout'; 120 | String _channelMethod = 'post_method_call'; 121 | int retryCount = 3; 122 | 123 | /// [timeout] request timeout in milliseconds 124 | int timeout; 125 | VKResponseParser parser = VKApiResponseParser(); 126 | 127 | VKPostMethodCall(String url) : super(url); 128 | 129 | @override 130 | Map getChannelArguments() { 131 | final Map res = {_urlStr: getEndpoint()}; 132 | if (_args?.isNotEmpty == true) res[_argumentsStr] = _args; 133 | if (retryCount != null) res[_retryCountStr] = retryCount; 134 | if (timeout != null) res[_timeoutStr] = timeout; 135 | return res; 136 | } 137 | 138 | @override 139 | Future callMethod([arguments]) { 140 | return InternalErrorRetryChainCall(this).executeAsync(); 141 | } 142 | } 143 | 144 | class InternalErrorRetryChainCall { 145 | final VKPostMethodCall postCall; 146 | 147 | InternalErrorRetryChainCall(this.postCall); 148 | 149 | Future executeAsync() async { 150 | final request = http.MultipartRequest('POST', Uri.parse(postCall.getEndpoint())); 151 | final args = postCall.args; 152 | if (args != null) { 153 | for (var item in args.entries) { 154 | final path = Uri.parse(item.value).path; 155 | final file = await http.MultipartFile.fromPath(item.key, path); 156 | request.files.add(file); 157 | } 158 | } 159 | Duration timeLimit; 160 | if (postCall.timeout != null) timeLimit = Duration(milliseconds: postCall.timeout); 161 | // TODO: cancel request on timeout 162 | final response = await (timeLimit == null ? request.send() : request.send().timeout(timeLimit)); 163 | if (response.statusCode != 200) return null; 164 | final bodyContent = await utf8.decodeStream(response.stream); 165 | return bodyContent; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /lib/vk_response_parser.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | abstract class VKResponseParser { 4 | T parse(String response); 5 | } 6 | 7 | class VKApiResponseParser implements VKResponseParser { 8 | final _responseKey = 'response'; 9 | 10 | @override 11 | parse(String response) { 12 | final res = json.decode(response); 13 | if (res == null || !(res is Map) || !res.containsKey(_responseKey)) return res; 14 | return res[_responseKey]; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/vk_scope.dart: -------------------------------------------------------------------------------- 1 | class VKScope { 2 | static const String notify = 'notify'; 3 | static final String friends = 'friends'; 4 | static final String photos = 'photos'; 5 | static final String audio = 'audio'; 6 | static final String stories = 'stories'; 7 | static final String pages = 'pages'; 8 | static final String status = 'status'; 9 | static final String notes = 'notes'; 10 | static final String messages = 'messages'; 11 | static final String wall = 'wall'; 12 | static final String ads = 'ads'; 13 | static final String offline = 'offline'; 14 | static final String video = 'video'; 15 | static final String docs = 'docs'; 16 | static final String groups = 'groups'; 17 | static final String notifications = 'notifications'; 18 | static final String stats = 'stats'; 19 | static final String email = 'email'; 20 | static final String market = 'market'; 21 | static final String phone = 'phone'; 22 | } 23 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.1.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.0.4" 18 | charcode: 19 | dependency: transitive 20 | description: 21 | name: charcode 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.2" 25 | collection: 26 | dependency: transitive 27 | description: 28 | name: collection 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.14.11" 32 | flutter: 33 | dependency: "direct main" 34 | description: flutter 35 | source: sdk 36 | version: "0.0.0" 37 | flutter_test: 38 | dependency: "direct dev" 39 | description: flutter 40 | source: sdk 41 | version: "0.0.0" 42 | http: 43 | dependency: "direct main" 44 | description: 45 | name: http 46 | url: "https://pub.dartlang.org" 47 | source: hosted 48 | version: "0.12.0+2" 49 | http_parser: 50 | dependency: transitive 51 | description: 52 | name: http_parser 53 | url: "https://pub.dartlang.org" 54 | source: hosted 55 | version: "3.1.3" 56 | matcher: 57 | dependency: transitive 58 | description: 59 | name: matcher 60 | url: "https://pub.dartlang.org" 61 | source: hosted 62 | version: "0.12.5" 63 | meta: 64 | dependency: transitive 65 | description: 66 | name: meta 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "1.1.6" 70 | path: 71 | dependency: transitive 72 | description: 73 | name: path 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "1.6.2" 77 | pedantic: 78 | dependency: transitive 79 | description: 80 | name: pedantic 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "1.5.0" 84 | quiver: 85 | dependency: transitive 86 | description: 87 | name: quiver 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "2.0.2" 91 | sky_engine: 92 | dependency: transitive 93 | description: flutter 94 | source: sdk 95 | version: "0.0.99" 96 | source_span: 97 | dependency: transitive 98 | description: 99 | name: source_span 100 | url: "https://pub.dartlang.org" 101 | source: hosted 102 | version: "1.5.5" 103 | stack_trace: 104 | dependency: transitive 105 | description: 106 | name: stack_trace 107 | url: "https://pub.dartlang.org" 108 | source: hosted 109 | version: "1.9.3" 110 | stream_channel: 111 | dependency: transitive 112 | description: 113 | name: stream_channel 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "2.0.0" 117 | string_scanner: 118 | dependency: transitive 119 | description: 120 | name: string_scanner 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.0.4" 124 | term_glyph: 125 | dependency: transitive 126 | description: 127 | name: term_glyph 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.1.0" 131 | test_api: 132 | dependency: transitive 133 | description: 134 | name: test_api 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "0.2.4" 138 | typed_data: 139 | dependency: transitive 140 | description: 141 | name: typed_data 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.1.6" 145 | vector_math: 146 | dependency: transitive 147 | description: 148 | name: vector_math 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "2.0.8" 152 | sdks: 153 | dart: ">=2.2.0 <3.0.0" 154 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_vk_sdk 2 | description: Flutter vk sdk project. 3 | version: 0.1.0+3 4 | homepage: 'https://github.com/kyuqw/flutter_vk_sdk' 5 | 6 | environment: 7 | sdk: ">=2.1.0 <3.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | http: ^0.12.0+4 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | 19 | # For information on the generic Dart part of this file, see the 20 | # following page: https://www.dartlang.org/tools/pub/pubspec 21 | 22 | # The following section is specific to Flutter. 23 | flutter: 24 | # This section identifies this Flutter project as a plugin project. 25 | # The androidPackage and pluginClass identifiers should not ordinarily 26 | # be modified. They are used by the tooling to maintain consistency when 27 | # adding or updating assets for this project. 28 | plugin: 29 | androidPackage: com.kf.flutter_vk_sdk 30 | pluginClass: FlutterVKSdkPlugin 31 | 32 | # To add assets to your plugin package, add an assets section, like this: 33 | # assets: 34 | # - images/a_dot_burr.jpeg 35 | # - images/a_dot_ham.jpeg 36 | # 37 | # For details regarding assets in packages, see 38 | # https://flutter.dev/assets-and-images/#from-packages 39 | # 40 | # An image asset can refer to one or more resolution-specific "variants", see 41 | # https://flutter.dev/assets-and-images/#resolution-aware. 42 | 43 | # To add custom fonts to your plugin package, add a fonts section here, 44 | # in this "flutter" section. Each entry in this list should have a 45 | # "family" key with the font family name, and a "fonts" key with a 46 | # list giving the asset and other descriptors for the font. For 47 | # example: 48 | # fonts: 49 | # - family: Schyler 50 | # fonts: 51 | # - asset: fonts/Schyler-Regular.ttf 52 | # - asset: fonts/Schyler-Italic.ttf 53 | # style: italic 54 | # - family: Trajan Pro 55 | # fonts: 56 | # - asset: fonts/TrajanPro.ttf 57 | # - asset: fonts/TrajanPro_Bold.ttf 58 | # weight: 700 59 | # 60 | # For details regarding fonts in packages, see 61 | # https://flutter.dev/custom-fonts/#from-packages 62 | -------------------------------------------------------------------------------- /test/flutter_vk_sdk_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | //import 'package:flutter_vk_sdk/flutter_vk_sdk.dart'; 4 | 5 | void main() { 6 | const MethodChannel channel = MethodChannel('com.fb.fluttervksdk/vk'); 7 | 8 | setUp(() { 9 | channel.setMockMethodCallHandler((MethodCall methodCall) async { 10 | return '42'; 11 | }); 12 | }); 13 | 14 | tearDown(() { 15 | channel.setMockMethodCallHandler(null); 16 | }); 17 | 18 | // TODO: write tests 19 | // test('getPlatformVersion', () async { 20 | // expect(await FlutterVKSdk.platformVersion, '42'); 21 | // }); 22 | } 23 | --------------------------------------------------------------------------------