add new dependency

This commit is contained in:
otsmr 2025-12-27 14:15:36 +01:00
parent 83475a9128
commit 9d1f1bc4ed
37 changed files with 2263 additions and 2003 deletions

3
.gitignore vendored
View file

@ -1,2 +1,3 @@
.venv
.dart_tool
.dart_tool
.flutter-plugins-dependencies

View file

@ -1,6 +1,7 @@
adaptive_number: ea9178fdd4d82ac45cf0ec966ac870dae661124f
dots_indicator: 508f5883ac79bdbc10254092de3f28f571d261cd
ed25519_edwards: 7353ba759ea9f4646cbf481c2ef949625c8ce4cf
flutter_sharing_intent: aa1672f547d6579585fa27df0b28ffa2a2544aaa
hand_signature: 1beedb164d093643365b0832277c377353c7464f
hashlib: 983cdbd5ee2529b908876b57a7217c09c6bc148a
hashlib_codecs: 2a966c37c3b9b1f5541ae88e99ab34acf3fc968b

View file

@ -46,4 +46,7 @@ libsignal_protocol_dart:
git: https://github.com/Tougee/curve25519.git
hand_signature:
git: https://github.com/RomanBase/hand_signature.git
git: https://github.com/RomanBase/hand_signature.git
flutter_sharing_intent:
git: https://github.com/bhagat-techind/flutter_sharing_intent.git

View file

@ -1,71 +0,0 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
characters:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.4.0"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1"
url: "https://pub.dev"
source: hosted
version: "5.0.0"
lints:
dependency: transitive
description:
name: lints
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
url: "https://pub.dev"
source: hosted
version: "5.1.1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
source: hosted
version: "1.17.0"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev"
source: hosted
version: "2.2.0"
sdks:
dart: ">=3.8.0-0 <4.0.0"

View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -0,0 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.cxx

View file

@ -0,0 +1,53 @@
group 'com.techind.flutter_sharing_intent'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '2.1.20'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
namespace 'com.techind.flutter_sharing_intent'
compileSdkVersion 36
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
minSdkVersion 21
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}

View file

@ -0,0 +1 @@
rootProject.name = 'flutter_sharing_intent'

View file

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.techind.flutter_sharing_intent">
<!-- <application>-->
<!-- <activity-->
<!-- android:name=".MainActivity"-->
<!-- android:configChanges="orientation|keyboardHidden|screenSize"-->
<!-- android:exported="true"-->
<!-- android:theme="@style/LaunchTheme"-->
<!-- android:hardwareAccelerated="true"-->
<!-- android:windowSoftInputMode="adjustResize"-->
<!-- android:screenOrientation="portrait"-->
<!-- android:launchMode="singleTask">-->
<!-- &lt;!&ndash;TODO: Add this filter, if you want to support sharing text into your app&ndash;&gt;-->
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.SEND" />-->
<!-- <category android:name="android.intent.category.DEFAULT" />-->
<!-- <data android:mimeType="text/*" />-->
<!-- </intent-filter>-->
<!-- &lt;!&ndash;TODO: Add this filter, if you want to support sharing images into your app&ndash;&gt;-->
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.SEND" />-->
<!-- <category android:name="android.intent.category.DEFAULT" />-->
<!-- <data android:mimeType="image/*" />-->
<!-- </intent-filter>-->
<!-- &lt;!&ndash;TODO: Add this filter, if you want to support sharing multi images into your app&ndash;&gt;-->
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.SEND_MULTIPLE" />-->
<!-- <category android:name="android.intent.category.DEFAULT" />-->
<!-- <data android:mimeType="image/*" />-->
<!-- </intent-filter>-->
<!-- &lt;!&ndash;TODO: Add this filter, if you want to support sharing videos into your app&ndash;&gt;-->
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.SEND" />-->
<!-- <category android:name="android.intent.category.DEFAULT" />-->
<!-- <data android:mimeType="video/*" />-->
<!-- </intent-filter>-->
<!-- &lt;!&ndash;TODO: Add this filter, if you want to support sharing multi videos into your app&ndash;&gt;-->
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.SEND_MULTIPLE" />-->
<!-- <category android:name="android.intent.category.DEFAULT" />-->
<!-- <data android:mimeType="video/*" />-->
<!-- </intent-filter>-->
<!-- &lt;!&ndash;TODO: Add this filter, if you want to support sharing any type of files&ndash;&gt;-->
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.SEND" />-->
<!-- <category android:name="android.intent.category.DEFAULT" />-->
<!-- <data android:mimeType="*/*" />-->
<!-- </intent-filter>-->
<!-- &lt;!&ndash;TODO: Add this filter, if you want to support sharing multiple files of any type&ndash;&gt;-->
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.SEND_MULTIPLE" />-->
<!-- <category android:name="android.intent.category.DEFAULT" />-->
<!-- <data android:mimeType="*/*" />-->
<!-- </intent-filter>-->
<!-- <meta-data-->
<!-- android:name="android.app.lib_name"-->
<!-- android:value="" />-->
<!-- </activity>-->
<!-- </application>-->
</manifest>

View file

@ -0,0 +1,314 @@
package com.techind.flutter_sharing_intent
import android.app.SearchManager
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.media.MediaMetadataRetriever
import android.media.ThumbnailUtils
import android.net.Uri
import android.provider.MediaStore
import android.util.Log
import android.webkit.URLUtil
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.*
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.io.FileOutputStream
import java.net.URLConnection
private const val EVENTS_CHANNEL_MEDIA = "flutter_sharing_intent/events-sharing"
/**
** Author - Bhagat Singh
** Contact - https://www.linkedin.com/in/bhagat-singh-79496a14b/
** Created On - 25/11/2022
** Purpose - Created [FlutterSharingIntentPlugin] class to manage sharing intent
*/
class FlutterSharingIntentPlugin: FlutterPlugin, ActivityAware, MethodCallHandler,
EventChannel.StreamHandler,
PluginRegistry.NewIntentListener {
private var TAG:String = javaClass.name
/** To store initial & latest value when app is opened from background **/
private var initialSharing: JSONArray? = null
private var latestSharing: JSONArray? = null
/// The MethodChannel that will the communication between Flutter and native Android
private lateinit var channel : MethodChannel
private lateinit var eventChannel: EventChannel
private var eventSinkSharing: EventChannel.EventSink? = null
private var binding: ActivityPluginBinding? = null
private lateinit var applicationContext: Context
/// To sel channel & event stream
private fun setupCallbackChannels(binaryMessenger: BinaryMessenger) {
channel = MethodChannel(binaryMessenger, "flutter_sharing_intent")
channel.setMethodCallHandler(this)
eventChannel = EventChannel(binaryMessenger, EVENTS_CHANNEL_MEDIA)
eventChannel.setStreamHandler(this)
}
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
applicationContext = flutterPluginBinding.applicationContext
setupCallbackChannels(flutterPluginBinding.binaryMessenger)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
when (call.method) {
"getInitialSharing" -> {
result.success(initialSharing?.toString())
/// Clear cache data to send only once
initialSharing = null
latestSharing = null
}
"reset" -> {
initialSharing = null
latestSharing = null
result.success(null)
}
else -> result.notImplemented()
}
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
initialSharing = null
latestSharing = null
eventChannel.setStreamHandler(null)
}
private fun handleIntent(intent: Intent, initial: Boolean) {
val intentFlags = intent.getFlags()
if ((intentFlags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0){
Log.w(TAG,"handleIntent ==>> ${intent.action}, ${intent.type}")
when {
(intent.type?.startsWith("text") != true)
&& (intent.action == Intent.ACTION_SEND
|| intent.action == Intent.ACTION_SEND_MULTIPLE) -> { // Sharing images or videos
val value = getSharingUris(intent)
if (initial) initialSharing = value
latestSharing = value
Log.w(TAG,"Image/Video : handleIntent ==>> $value")
eventSinkSharing?.success(value?.toString())
}
(intent.type == null || intent.type?.startsWith("text") == true)
&& (intent.action == Intent.ACTION_SEND || intent.action == Intent.ACTION_SEND_MULTIPLE) -> { // Sharing text
val value = getSharingText(intent) ?: getSharingUris(intent)
if (initial) initialSharing = value
latestSharing = value
Log.w(TAG,"text : handleIntent ==>> $value")
// Log.w(TAG,"text : handleIntent ==>> ${eventSinkSharing!=null}")
eventSinkSharing?.success(value?.toString())
}
intent.action == Intent.ACTION_VIEW -> { // Opening URL
val value = JSONArray().put(
JSONObject()
.put("value", intent.dataString)
.put("type", MediaType.URL.ordinal)
)
if (initial) initialSharing = value
latestSharing = value
Log.w(TAG,"ACTION_VIEW : handleIntent ==>> $value")
eventSinkSharing?.success(value?.toString())
}
intent.action == Intent.ACTION_WEB_SEARCH -> {
val value = JSONArray().put(
JSONObject()
.put("value", intent.getStringExtra(SearchManager.QUERY))
.put("type", MediaType.WEB_SEARCH.ordinal)
)
if (initial) initialSharing = value
latestSharing = value
Log.w(TAG,"ACTION_WEB_SEARCH : handleIntent ==>> $value")
eventSinkSharing?.success(value?.toString())
}
}
}
}
private fun getSharingUris(intent: Intent?): JSONArray? {
if (intent == null) return null
return when (intent.action) {
Intent.ACTION_SEND -> {
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
val path = uri?.let{ MyFileDirectory.getAbsolutePath(applicationContext, it) }
if (path != null) {
val type = getMediaType(path)
val thumbnail = getThumbnail(path, type)
val duration = getDuration(path, type)
JSONArray().put(
JSONObject()
.put("value", path)
.put("type", type.ordinal)
.put("thumbnail", thumbnail)
.put("duration", duration)
)
} else null
}
Intent.ACTION_SEND_MULTIPLE -> {
val uris = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
val value = uris?.mapNotNull { uri ->
val path = MyFileDirectory.getAbsolutePath(applicationContext, uri)
?: return@mapNotNull null
val type = getMediaType(path)
val thumbnail = getThumbnail(path, type)
val duration = getDuration(path, type)
return@mapNotNull JSONObject()
.put("value", path)
.put("type", type.ordinal)
.put("thumbnail", thumbnail)
.put("duration", duration)
}?.toList()
if (value != null) JSONArray(value) else null
}
else -> null
}
}
private fun getSharingText(intent: Intent?): JSONArray? {
if (intent == null) return null
return when (intent.action) {
Intent.ACTION_SEND -> {
val text = intent.getStringExtra(Intent.EXTRA_TEXT)
if (text != null) {
val type = getTypeForTextAndUrl(text)
JSONArray().put(
JSONObject()
.put("value", text)
.put("type", type)
)
} else null
}
Intent.ACTION_SEND_MULTIPLE -> {
val textList = intent.getStringArrayListExtra(Intent.EXTRA_TEXT)
val value = textList?.mapNotNull { text ->
val path = text
?: return@mapNotNull null
val type = getTypeForTextAndUrl(path)
return@mapNotNull JSONObject()
.put("value", path)
.put("type", type)
}?.toList()
if (value != null) JSONArray(value) else null
}
else -> null
}
}
// To get type for text and url only
// It will return MediaType.URL.ordinal if text is valid url other will return MediaType.TEXT.ordinal
fun getTypeForTextAndUrl( value: String?) : Int
{
return if (value == null || !URLUtil.isValidUrl(value)) MediaType.TEXT.ordinal else MediaType.URL.ordinal;
}
private fun getMediaType(path: String?): MediaType {
val mimeType = URLConnection.guessContentTypeFromName(path)
return when {
mimeType?.startsWith("image") == true -> MediaType.IMAGE
mimeType?.startsWith("video") == true -> MediaType.VIDEO
mimeType?.startsWith("text") == true -> MediaType.TEXT
mimeType?.startsWith("url") == true -> MediaType.URL
mimeType?.startsWith("web_search") == true -> MediaType.WEB_SEARCH
else -> MediaType.FILE
}
}
private fun getThumbnail(path: String, type: MediaType): String? {
if (type != MediaType.VIDEO) return null // get video thumbnail only
val videoFile = File(path)
val targetFile = File(applicationContext.cacheDir, "${videoFile.name}.png")
val bitmap = ThumbnailUtils.createVideoThumbnail(path, MediaStore.Video.Thumbnails.MINI_KIND)
?: return null
FileOutputStream(targetFile).use { out ->
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
}
bitmap.recycle()
return targetFile.path
}
private fun getDuration(path: String, type: MediaType): Long? {
if (type != MediaType.VIDEO) return null // get duration for video only
val retriever = MediaMetadataRetriever()
retriever.setDataSource(path)
val duration = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLongOrNull()
retriever.release()
return duration
}
enum class MediaType {
TEXT, URL, IMAGE, VIDEO, FILE, WEB_SEARCH ;
}
override fun onNewIntent(intent: Intent): Boolean {
handleIntent(intent, false)
return false
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
this.binding = binding
binding.addOnNewIntentListener(this)
handleIntent(binding.activity.intent, true)
}
override fun onDetachedFromActivityForConfigChanges() {
binding?.removeOnNewIntentListener(this)
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
this.binding = binding
binding.addOnNewIntentListener(this)
}
override fun onDetachedFromActivity() {
binding?.removeOnNewIntentListener(this)
}
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
Log.d(TAG,"onListen ==>> $arguments, $events")
when (arguments) {
// "sharing" -> eventSinkSharing = events
"sharing" -> {
eventSinkSharing = events
latestSharing?.let {
Log.d(TAG, "Sending cached sharing data onListen: $it")
// eventSinkSharing?.success(it.toString())
}
}
}
}
override fun onCancel(arguments: Any?) {
Log.d(TAG,"onCancel ==>> $arguments")
when (arguments) {
"sharing" -> eventSinkSharing = null
}
}
}

View file

@ -0,0 +1,177 @@
package com.techind.flutter_sharing_intent
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.util.Log
import android.webkit.MimeTypeMap
import java.io.File
import java.io.FileOutputStream
import java.util.*
/**
** Author - Bhagat Singh
** Contact - https://www.linkedin.com/in/bhagat-singh-79496a14b/
** Created On - 25/11/2022
** Purpose - Created [MyFileDirectory] to get path of a file
*/
object MyFileDirectory {
/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @author paulburke
*/
fun getAbsolutePath(context: Context, uri: Uri): String? {
// DocumentProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
return if ("primary".equals(type, ignoreCase = true)) {
Environment.getExternalStorageDirectory().toString() + "/" + split[1]
} else {
getDataColumn(context, uri, null, null)
}
} else if (isDownloadsDocument(uri)) {
return try {
val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
getDataColumn(context, contentUri, null, null)
} catch (exception: Exception) {
getDataColumn(context, uri, null, null)
}
} else if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
var contentUri: Uri? = null
when (type) {
"image" -> contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
"video" -> contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
"audio" -> contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
if (contentUri == null) return null
val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
return getDataColumn(context, contentUri, selection, selectionArgs)
}// MediaProvider
// DownloadsProvider
} else if ("content".equals(uri.scheme, ignoreCase = true)) {
return getDataColumn(context, uri, null, null)
}
return uri.path
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
private fun getDataColumn(context: Context, uri: Uri, selection: String?,
selectionArgs: Array<String>?): String? {
if (uri.authority != null) {
var cursor: Cursor? = null
val column = "_display_name"
val projection = arrayOf(column)
var targetFile: File? = null
try {
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(column)
val fileName = cursor.getString(columnIndex)
Log.i("FileDirectory", "File name: $fileName")
targetFile = File(context.cacheDir, fileName)
}
} finally {
cursor?.close()
}
if (targetFile == null) {
val mimeType = context.contentResolver.getType(uri)
val prefix = with(mimeType ?: "") {
when {
startsWith("image") -> "IMG"
startsWith("video") -> "VID"
else -> "FILE"
}
}
val type = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType)
targetFile = File(context.cacheDir, "${prefix}_${Date().time}.$type")
}
context.contentResolver.openInputStream(uri)?.use { input ->
FileOutputStream(targetFile).use { fileOut ->
input.copyTo(fileOut)
}
}
return targetFile.path
}
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(column)
try {
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(column)
return cursor.getString(columnIndex)
}
} finally {
cursor?.close()
}
return null
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
private fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
private fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
}

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1 @@
<resources></resources>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">?android:colorBackground</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

58
flutter_sharing_intent/ios/.gitignore vendored Normal file
View file

@ -0,0 +1,58 @@
.idea/
.vagrant/
.sconsign.dblite
.svn/
.DS_Store
*.swp
profile
DerivedData/
build/
GeneratedPluginRegistrant.h
GeneratedPluginRegistrant.m
.generated/
*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3
xcuserdata
*.moved-aside
*.pyc
*sync/
Icon?
.tags*
/Flutter/Generated.xcconfig
/Flutter/ephemeral/
/Flutter/flutter_export_environment.sh
Podfile.lock
**/dgph
**/*sync/
**/.vagrant/
**/DerivedData/
**/Pods/
**/.symlinks/
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*

View file

@ -0,0 +1,599 @@
// FSIShareViewController.swift
// Merged, optimized controller: uses RSI architecture with all FSI features preserved
// Uses model name `SharingFile` (same fields as SharedMediaFile) where `value` = path
import AVFoundation
import MobileCoreServices
import Social
import UIKit
import UniformTypeIdentifiers
public let kSchemePrefix = "SharingMedia"
public let kUserDefaultsKey = "SharingKey"
public let kUserDefaultsMessageKey = "SharingMessageKey"
public let kAppGroupIdKey = "AppGroupId"
public let kAppChannel = "flutter_sharing_intent"
// extension UIViewController {
// func showToast(_ message: String, duration: Double = 2.0) {
// let toastLabel = UILabel()
// toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.7)
// toastLabel.textColor = UIColor.white
// toastLabel.textAlignment = .center
// toastLabel.font = UIFont.systemFont(ofSize: 14)
// toastLabel.text = message
// toastLabel.alpha = 0.0
// toastLabel.numberOfLines = 0
// toastLabel.layer.cornerRadius = 10
// toastLabel.clipsToBounds = true
//
// let maxWidthPercentage: CGFloat = 0.8
// let maxMessageSize = CGSize(
// width: self.view.bounds.size.width * maxWidthPercentage,
// height: self.view.bounds.size.height * maxWidthPercentage
// )
//
// var expectedSize = toastLabel.sizeThatFits(maxMessageSize)
// expectedSize.width += 24
// expectedSize.height += 16
//
// toastLabel.frame = CGRect(
// x: (self.view.frame.size.width - expectedSize.width) / 2,
// y: self.view.frame.size.height - expectedSize.height - 50,
// width: expectedSize.width,
// height: expectedSize.height
// )
//
// self.view.addSubview(toastLabel)
//
// UIView.animate(withDuration: 0.5, animations: {
// toastLabel.alpha = 1.0
// }) { _ in
// UIView.animate(withDuration: 0.5, delay: duration, options: .curveEaseOut, animations: {
// toastLabel.alpha = 0.0
// }) { _ in
// toastLabel.removeFromSuperview()
// }
// }
// }
// }
// @objc(FSIShareViewController)
@available(swift, introduced: 5.0)
open class FSIShareViewController: SLComposeServiceViewController {
// MARK: - Config
private(set) var hostAppBundleIdentifier: String = ""
private(set) var appGroupId: String = ""
// Results
private var sharedMedia: [SharingFile] = []
// Debug
private let debugLogs = false
// MARK: - Lifecycle
open override func viewDidLoad() {
super.viewDidLoad()
loadIds()
}
open override func isContentValid() -> Bool {
return true
}
open override func didSelectPost() {
if self.sharedMedia.isEmpty {
if let text = self.contentText, !text.isEmpty {
self.sharedMedia.append(
SharingFile(value: text, thumbnail: nil, duration: nil, type: .text)
)
self.saveAndRedirect(message: text)
return
}
self.completeAndExit()
} else {
self.saveAndRedirect()
}
// If the UI Post is used, save and redirect using contentText
// saveAndRedirect(message: contentText)
}
open override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Process attachments automatically on appear like original FSI
processAttachments()
}
// MARK: - Load Ids
private func loadIds() {
let shareExtId = Bundle.main.bundleIdentifier ?? ""
if let idx = shareExtId.lastIndex(of: ".") {
hostAppBundleIdentifier = String(shareExtId[..<idx])
} else {
hostAppBundleIdentifier = shareExtId
}
let custom = Bundle.main.object(forInfoDictionaryKey: kAppGroupIdKey) as? String
appGroupId = custom ?? "group.\(hostAppBundleIdentifier)"
log("loaded host=\(hostAppBundleIdentifier) group=\(appGroupId)")
}
// MARK: - Attachment processing (clean RSI style, preserve FSI features)
private func processAttachments() {
guard let content = extensionContext?.inputItems.first as? NSExtensionItem else {
completeAndExit()
return
}
guard let attachments = content.attachments, !attachments.isEmpty else {
completeAndExit()
return
}
// Use DispatchGroup to wait for async loads
let group = DispatchGroup()
for (index, provider) in attachments.enumerated() {
group.enter()
// Try all SharedMediaType options similar to RSI but preserve explicit FSI order
if provider.isImage {
provider.loadItem(forTypeIdentifier: UType.image, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleImageItem(data: data, index: index, total: attachments.count)
}
continue
}
if provider.isMovie {
provider.loadItem(forTypeIdentifier: UType.movie, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleVideoItem(data: data, index: index, total: attachments.count)
}
continue
}
if provider.isFile {
provider.loadItem(forTypeIdentifier: UType.fileURL, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleFileItem(data: data, index: index, total: attachments.count)
}
continue
}
if provider.isURL {
provider.loadItem(forTypeIdentifier: UType.url, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleUrlItem(data: data, index: index, total: attachments.count)
}
continue
}
if provider.isText {
let id = provider.hasItemConformingToTypeIdentifier(UType.plainText)
? UType.plainText
: UType.text
provider.loadItem(forTypeIdentifier: id, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleTextItem(data: data, index: index, total: attachments.count)
}
continue
}
if provider.isData {
provider.loadItem(forTypeIdentifier: UType.data, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleFileItem(data: data, index: index, total: attachments.count)
}
continue
}
if provider.isItem {
provider.loadItem(forTypeIdentifier: UType.item, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleFileItem(data: data, index: index, total: attachments.count)
}
continue
}
log("Unknown provider type: \(provider.registeredTypeIdentifiers)")
// Unknown type: just leave
group.leave()
}
group.notify(queue: .main) { [weak self] in
guard let self = self else { return }
// if we have media -> media, else fallback to complete
if !self.sharedMedia.isEmpty {
self.saveAndRedirect()
} else {
print("FSIShare: No shared media → stopping.")
self.completeAndExit()
}
}
}
// MARK: - Individual handlers (preserve FSI behavior)
private func handleTextItem(data: NSSecureCoding?, index: Int, total: Int) {
if let s = data as? String {
sharedMedia.append(SharingFile(value: s, thumbnail: nil, duration: nil, type: .text))
} else if let url = data as? URL {
sharedMedia.append(SharingFile(value: url.absoluteString, thumbnail: nil, duration: nil, type: .url))
}
}
private func handleUrlItem(data: NSSecureCoding?, index: Int, total: Int) {
if let url = data as? URL {
sharedMedia.append(SharingFile(value: url.absoluteString, thumbnail: nil, duration: nil, type: .url))
} else if let s = data as? String {
sharedMedia.append(SharingFile(value: s, thumbnail: nil, duration: nil, type: .text))
}
}
private func handleImageItem(data: NSSecureCoding?, index: Int, total: Int) {
// data can be URL, UIImage, or Data
if let url = data as? URL {
let filename = getFileName(from: url, type: .image)
if let dst = containerURL()?.appendingPathComponent(filename) {
if copyFile(at: url, to: dst) {
sharedMedia.append(SharingFile(value: dst.absoluteString, mimeType: url.mimeType(), thumbnail: nil, duration: nil, type: .image))
}
}
} else if let img = data as? UIImage {
if let saved = writeTempImage(img) {
sharedMedia.append(saved)
}
} else if let raw = data as? Data, let img = UIImage(data: raw) {
if let saved = writeTempImage(img) {
sharedMedia.append(saved)
}
}
}
private func handleVideoItem(data: NSSecureCoding?, index: Int, total: Int) {
if let url = data as? URL {
let filename = getFileName(from: url, type: .video)
if let dst = containerURL()?.appendingPathComponent(filename) {
if copyFile(at: url, to: dst) {
if let m = getSharedMediaFile(forVideo: dst) {
sharedMedia.append(m)
}
}
}
}
}
private func handleFileItem(data: NSSecureCoding?, index: Int, total: Int) {
if let url = data as? URL {
let filename = getFileName(from: url, type: .file)
if let dst = containerURL()?.appendingPathComponent(filename) {
if copyFile(at: url, to: dst) {
sharedMedia.append(SharingFile(value: dst.absoluteString, mimeType: url.mimeType(), thumbnail: nil, duration: nil, type: .file))
}
}
}
else if let raw = data as? Data {
let filename = "File_\(UUID().uuidString)"
if let dst = containerURL()?.appendingPathComponent(filename) {
do {
try raw.write(to: dst)
sharedMedia.append(SharingFile(value: dst.absoluteString, mimeType: "application/octet-stream", thumbnail: nil, duration: nil, type: .file))
} catch {}
}
}
}
// MARK: - Helpers: write temp image
private func writeTempImage(_ image: UIImage) -> SharingFile? {
guard let container = containerURL() else { return nil }
let tempName = "TempImage_\(UUID().uuidString).png"
let dst = container.appendingPathComponent(tempName)
do {
if let d = image.pngData() {
try d.write(to: dst)
let decoded = dst.absoluteString.removingPercentEncoding ?? dst.absoluteString
return SharingFile(value: decoded, mimeType: "image/png", thumbnail: nil, duration: nil, type: .image)
}
} catch {
log("writeTempImage error: \(error)")
}
return nil
}
private func saveAndRedirect(message: String? = nil) {
let ud = UserDefaults(suiteName: appGroupId)
if !sharedMedia.isEmpty {
if let data = try? JSONEncoder().encode(sharedMedia) {
ud?.set(data, forKey: kUserDefaultsKey)
}
}
ud?.set(message, forKey: kUserDefaultsMessageKey)
ud?.synchronize()
redirectToHostApp()
}
private func redirectToHostApp() {
// kept for compatibility (RSI style)
loadIds()
// let raw = "\(kSchemePrefix)-\(hostAppBundleIdentifier):share"
let raw = "\(kSchemePrefix)-\(hostAppBundleIdentifier)://dataUrl=\(kUserDefaultsKey)"
guard let url = URL(string: raw.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? raw) else { completeAndExit(); return }
var responder: UIResponder? = self
if #available(iOS 18.0, *) {
while responder != nil {
if let app = responder as? UIApplication { app.open(url, options: [:], completionHandler: nil) }
responder = responder?.next
}
} else {
let sel = sel_registerName("openURL:")
while responder != nil {
if responder?.responds(to: sel) ?? false { _ = responder?.perform(sel, with: url) }
responder = responder?.next
}
}
extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
}
// MARK: - File / thumbnail / metadata helpers
func getExtension(from url: URL, type: SharingFileType) -> String {
let parts = url.lastPathComponent.components(separatedBy: ".")
var ex: String? = nil
if parts.count > 1 { ex = parts.last }
if ex == nil {
switch type {
case .image: ex = "png"
case .video: ex = "mp4"
case .file: ex = "txt"
case .text: ex = "txt"
case .url: ex = "txt"
}
}
return ex ?? "bin"
}
func getFileName(from url: URL, type: SharingFileType) -> String {
var name = url.lastPathComponent
if name.isEmpty { name = UUID().uuidString + "." + getExtension(from: url, type: type) }
return name
}
func copyFile(at srcURL: URL, to dstURL: URL) -> Bool {
do {
if FileManager.default.fileExists(atPath: dstURL.path) { try FileManager.default.removeItem(at: dstURL) }
try FileManager.default.copyItem(at: srcURL, to: dstURL)
return true
} catch {
log("copyFile error: \(error)")
return false
}
}
private func getSharedMediaFile(forVideo: URL) -> SharingFile? {
let asset = AVAsset(url: forVideo)
let duration = (CMTimeGetSeconds(asset.duration) * 1000).rounded()
let thumbnailPath = getThumbnailPath(for: forVideo)
if FileManager.default.fileExists(atPath: thumbnailPath.path) {
return SharingFile(value: forVideo.absoluteString, mimeType: forVideo.mimeType(), thumbnail: thumbnailPath.absoluteString, duration: Int(duration), type: .video)
}
let gen = AVAssetImageGenerator(asset: asset)
gen.appliesPreferredTrackTransform = true
gen.maximumSize = CGSize(width: 360, height: 360)
// Use first second or zero
let time = CMTime(seconds: min(1.0, CMTimeGetSeconds(asset.duration)), preferredTimescale: 600)
do {
let cg = try gen.copyCGImage(at: time, actualTime: nil)
if let data = UIImage(cgImage: cg).jpegData(compressionQuality: 0.8) {
try data.write(to: thumbnailPath)
return SharingFile(value: forVideo.absoluteString, mimeType: forVideo.mimeType(), thumbnail: thumbnailPath.absoluteString, duration: Int(duration), type: .video)
}
} catch {
log("getSharedMediaFile thumbnail error: \(error)")
}
// fallback
return SharingFile(value: forVideo.absoluteString, mimeType: forVideo.mimeType(), thumbnail: nil, duration: Int(duration), type: .video)
}
private func getThumbnailPath(for url: URL) -> URL {
guard let container = containerURL() else { fatalError("App group not configured or missing") }
let fileName = Data(url.lastPathComponent.utf8).base64EncodedString().replacingOccurrences(of: "=", with: "")
return container.appendingPathComponent("\(fileName).jpg")
}
private func containerURL() -> URL? {
FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupId)
}
private func completeAndExit() {
extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
}
private func dismissWithError() {
log("[ERROR] Error loading data!")
let alert = UIAlertController(title: "Error", message: "Error loading data", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel) { _ in self.dismiss(animated: true, completion: nil) })
present(alert, animated: true, completion: nil)
extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
}
private func writeTempFile(_ image: UIImage, to dstURL: URL) -> Bool {
do {
if FileManager.default.fileExists(atPath: dstURL.path) { try FileManager.default.removeItem(at: dstURL) }
let pngData = image.pngData()
try pngData?.write(to: dstURL)
return true
} catch (let error) {
log("writeTempFile error: \(error)")
return false
}
}
private func saveToUserDefaults(data: [SharingFile]) {
let ud = UserDefaults(suiteName: appGroupId)
if let enc = try? JSONEncoder().encode(data) { ud?.set(enc, forKey: kUserDefaultsKey); ud?.synchronize() }
}
// MARK: - Logging
private func log(_ s: String) { if debugLogs { print("[FSIShareVC] \(s)") } }
}
// MARK: - Extensions
extension URL {
func mimeType() -> String {
if #available(iOS 14.0, *) {
if let ut = UTType(filenameExtension: self.pathExtension), let m = ut.preferredMIMEType { return m }
} else {
if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, self.pathExtension as NSString, nil)?.takeRetainedValue() {
if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() { return mimetype as String }
}
}
return "application/octet-stream"
}
}
extension NSItemProvider {
var isImage: Bool { return hasItemConformingToTypeIdentifier(UType.image) }
var isMovie: Bool { return hasItemConformingToTypeIdentifier(UType.movie) }
var isText: Bool {
hasItemConformingToTypeIdentifier(UType.plainText) || hasItemConformingToTypeIdentifier(UType.text)
}
var isURL: Bool { return hasItemConformingToTypeIdentifier(UType.url) }
var isFile: Bool { return hasItemConformingToTypeIdentifier(UType.fileURL) }
var isData:Bool { return hasItemConformingToTypeIdentifier(UType.data) }
var isItem: Bool { hasItemConformingToTypeIdentifier(UType.item) }
}
extension Array {
subscript(safe index: UInt) -> Element? { return Int(index) < count ? self[Int(index)] : nil }
}
class SharingFile: Codable {
var value: String
var mimeType: String?
var thumbnail: String?; // video thumbnail
var duration: Int?; // video duration in milliseconds
var type: SharingFileType;
var message: String? // post message
enum CodingKeys: String, CodingKey {
case value
case mimeType
case thumbnail
case duration
case type
case message
}
init(value: String, mimeType: String? = nil, thumbnail: String?, duration: Int?,
type: SharingFileType, message: String?=nil) {
self.value = value
self.mimeType = mimeType
self.thumbnail = thumbnail
self.duration = duration
self.type = type
self.message = message
}
// Debug method to print out SharedMediaFile details in the console
func toString() {
print("[SharingFile] \n\tvalue: \(self.value)\n\tthumbnail: \(self.thumbnail ?? "--" )\n\tduration: \(self.duration ?? 0)\n\ttype: \(self.type)\n\tmimeType: \(String(describing: self.mimeType))\n\tmessage: \(String(describing: self.message))")
}
}
enum SharingFileType: Int, Codable {
case text
case url
case image
case video
case file
}
// Unified UTType works on iOS 1118
enum UType {
static var image: String {
if #available(iOS 14.0, *) {
return UTType.image.identifier
} else {
return kUTTypeImage as String // old API
}
}
static var movie: String {
if #available(iOS 14.0, *) {
return UTType.movie.identifier
} else {
return kUTTypeMovie as String
}
}
static var url: String {
if #available(iOS 14.0, *) {
return UTType.url.identifier
} else {
return kUTTypeURL as String
}
}
static var fileURL: String {
if #available(iOS 14.0, *) {
return UTType.fileURL.identifier
} else {
return kUTTypeFileURL as String
}
}
static var text: String {
if #available(iOS 14.0, *) {
return UTType.text.identifier
} else {
return kUTTypeText as String
}
}
static var plainText: String {
if #available(iOS 14.0, *) {
return UTType.plainText.identifier
} else {
return kUTTypePlainText as String
}
}
static var data: String {
if #available(iOS 14.0, *) {
return UTType.data.identifier
} else {
return kUTTypeData as String
}
}
static var item: String {
if #available(iOS 14.0, *) {
return UTType.item.identifier
} else {
return kUTTypeItem as String
}
}
}

View file

@ -0,0 +1,4 @@
#import <Flutter/Flutter.h>
@interface FlutterSharingIntentPlugin : NSObject<FlutterPlugin>
@end

View file

@ -0,0 +1,15 @@
#import "FlutterSharingIntentPlugin.h"
#if __has_include(<flutter_sharing_intent/flutter_sharing_intent-Swift.h>)
#import <flutter_sharing_intent/flutter_sharing_intent-Swift.h>
#else
// Support project import fallback if the generated compatibility header
// is not copied when this plugin is created as a library.
// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
#import "flutter_sharing_intent-Swift.h"
#endif
@implementation FlutterSharingIntentPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
[SwiftFlutterSharingIntentPlugin registerWithRegistrar:registrar];
}
@end

View file

@ -0,0 +1,311 @@
import Flutter
import Photos
import UIKit
public class SwiftFlutterSharingIntentPlugin: NSObject, FlutterStreamHandler, FlutterPlugin {
static let kMessagesChannel = "\(kAppChannel)/messages"
static let kEventsChannelMedia = "\(kAppChannel)/events-sharing";
private var initialSharing: [SharingFile]? = nil
private var latestSharing: [SharingFile]? = nil
private var eventSinkMedia: FlutterEventSink? = nil;
// Singleton is required for calling functions directly from AppDelegate
// - it is required if the developer is using also another library, which requires to call "application(_:open:options:)"
// -> see Example app
public static let instance = SwiftFlutterSharingIntentPlugin()
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: kAppChannel,binaryMessenger:registrar.messenger())
registrar.addMethodCallDelegate(instance, channel: channel)
let chargingChannelMedia = FlutterEventChannel(name: kEventsChannelMedia, binaryMessenger: registrar.messenger())
chargingChannelMedia.setStreamHandler(instance)
registrar.addApplicationDelegate(instance)
// registrar.addMethodCallDelegate(instance, channel: channel)
}
// public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
// result("iOS " + UIDevice.current.systemVersion)
// }
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getInitialSharing":
result(toJson(data: self.initialSharing));
/// Clear cache data to send only once
self.initialSharing = nil
self.latestSharing = nil
case "reset":
self.initialSharing = nil
self.latestSharing = nil
result(nil);
case "getPlatformVersion" :
result("iOS " + UIDevice.current.systemVersion);
default:
result(FlutterMethodNotImplemented);
}
}
// By Adding bundle id to prefix, we will ensure that the correct app will be openned
public func hasSameSchemePrefix(url: URL?) -> Bool {
if let url = url, let appDomain = Bundle.main.bundleIdentifier {
return url.absoluteString.hasPrefix("\(kSchemePrefix)-\(appDomain)")
}
return false
}
// This is the function called on app startup with a shared link if the app had been closed already.
// It is called as the launch process is finishing and the app is almost ready to run.
// If the URL includes the module's ShareMedia prefix, then we process the URL and return true if we know how to handle that kind of URL or false if the app is not able to.
// If the URL does not include the module's prefix, we must return true since while our module cannot handle the link, other modules might be and returning false can prevent
// them from getting the chance to.
// Reference: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622921-application
public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [AnyHashable : Any] = [:]) -> Bool {
if let url = launchOptions[UIApplication.LaunchOptionsKey.url] as? URL {
if (hasSameSchemePrefix(url: url)) {
return handleUrl(url: url, setInitialData: true)
}
return true
} else if let activityDictionary = launchOptions[UIApplication.LaunchOptionsKey.userActivityDictionary] as? [AnyHashable: Any] {
// Handle multiple URLs shared in
for key in activityDictionary.keys {
if let userActivity = activityDictionary[key] as? NSUserActivity {
if let url = userActivity.webpageURL {
if (hasSameSchemePrefix(url: url)) {
return handleUrl(url: url, setInitialData: true)
}
return true
}
}
}
}
return true
}
// This is the function called on resuming the app from a shared link.
// It handles requests to open a resource by a specified URL. Returning true means that it was handled successfully, false means the attempt to open the resource failed.
// If the URL includes the module's ShareMedia prefix, then we process the URL and return true if we know how to handle that kind of URL or false if we are not able to.
// If the URL does not include the module's prefix, then we return false to indicate our module's attempt to open the resource failed and others should be allowed to.
// Reference: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623112-application
public func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
if (hasSameSchemePrefix(url: url)) {
return handleUrl(url: url, setInitialData: false)
}
return false
}
// This function is called by other modules like Firebase DeepLinks.
// It tells the delegate that data for continuing an activity is available. Returning true means that our module handled the activity and that others do not have to. Returning false tells
// iOS that our app did not handle the activity.
// If the URL includes the module's ShareMedia prefix, then we process the URL and return true if we know how to handle that kind of URL or false if we are not able to.
// If the URL does not include the module's prefix, then we must return false to indicate that this module did not handle the prefix and that other modules should try to.
// Reference: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623072-application
public func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]) -> Void) -> Bool {
if let url = userActivity.webpageURL {
if (hasSameSchemePrefix(url: url)) {
return handleUrl(url: url, setInitialData: true)
}
}
return false
}
private func handleUrl(url: URL?, setInitialData: Bool) -> Bool {
let appGroupId = Bundle.main.object(forInfoDictionaryKey: kAppGroupIdKey) as? String
let defaultGroupId = "group.\(Bundle.main.bundleIdentifier!)"
let userDefaults = UserDefaults(suiteName: appGroupId ?? defaultGroupId)
let message = userDefaults?.string(forKey: kUserDefaultsMessageKey)
if let json = userDefaults?.object(forKey: kUserDefaultsKey) as? Data {
let sharedArray = decode(data: json)
let sharedMediaFiles: [SharingFile] = sharedArray.compactMap {
guard let value = $0.type == .text || $0.type == .url ? $0.value
: getAbsolutePath(for: $0.value) else {
return nil
}
return SharingFile(
value: value,
mimeType: $0.mimeType,
thumbnail: getAbsolutePath(for: $0.thumbnail),
duration: $0.duration,
type: $0.type,
message: message
)
}
latestSharing = sharedMediaFiles
if(setInitialData) {
initialSharing = latestSharing
}
eventSinkMedia?(toJson(data: latestSharing))
}
return true
}
// private func handleUrl(url: URL?, setInitialData: Bool) -> Bool {
// if let url = url {
// let appGroupId = (Bundle.main.object(forInfoDictionaryKey: kAppGroupIdKey) as? String) ?? "group.\(Bundle.main.bundleIdentifier!)"
// let userDefaults = UserDefaults(suiteName: appGroupId)
// let message = userDefaults?.string(forKey: kUserDefaultsMessageKey)
// if let json = userDefaults?.object(forKey: kUserDefaultsKey) as? Data {
// print("SwiftFlutterSharingIntentPlugin : [handleUrl] \(json)")
// }
// if url.fragment == "media" {
// if let key = url.host?.components(separatedBy: "=").last,
// let json = userDefaults?.object(forKey: key) as? Data {
// let sharedArray = decode(data: json)
//
// let sharedMediaFiles: [SharingFile] = sharedArray.compactMap {
// guard let value = getAbsolutePath(for: $0.value) else {
// return nil
// }
// if ($0.type == .video && $0.thumbnail != nil) {
// let thumbnail = getAbsolutePath(for: $0.thumbnail!)
// return SharingFile.init(value: value, thumbnail: thumbnail, duration: $0.duration, type: $0.type)
// } else if ($0.type == .video && $0.thumbnail == nil) {
// return SharingFile.init(value: value, thumbnail: nil, duration: $0.duration, type: $0.type)
// }
//
// return SharingFile.init(value: value, thumbnail: nil, duration: $0.duration, type: $0.type)
// }
// latestSharing = sharedMediaFiles
// if(setInitialData) {
// initialSharing = latestSharing
// }
// eventSinkMedia?(toJson(data: latestSharing))
// }
// } else if url.fragment == "file" {
// if let key = url.host?.components(separatedBy: "=").last,
// let json = userDefaults?.object(forKey: key) as? Data {
// let sharedArray = decode(data: json)
// let sharedMediaFiles: [SharingFile] = sharedArray.compactMap{
// guard getAbsolutePath(for: $0.value) != nil else {
// return nil
// }
// return SharingFile.init(value: $0.value,
// thumbnail: nil, duration: nil,
// type: $0.type)
// }
// latestSharing = sharedMediaFiles
// if(setInitialData) {
// initialSharing = latestSharing
// }
// eventSinkMedia?(toJson(data: latestSharing))
// }
// } else if url.fragment == "url" {
// if let key = url.host?.components(separatedBy: "=").last,
// let sharedArray = userDefaults?.object(forKey: key) as? [String] {
// latestSharing = [SharingFile.init(value: sharedArray.joined(separator: ","), thumbnail: nil, duration: nil, type: SharingFileType.url)]
// if(setInitialData) {
// initialSharing = latestSharing
// }
// eventSinkMedia?(toJson(data: latestSharing))
// }
// } else if url.fragment == "text" {
// if let key = url.host?.components(separatedBy: "=").last,
// let sharedArray = userDefaults?.object(forKey: key) as? [String] {
// latestSharing = [SharingFile.init(value: sharedArray.joined(separator: ","), thumbnail: nil, duration: nil, type: SharingFileType.text)]
// if(setInitialData) {
// initialSharing = latestSharing
// }
// eventSinkMedia?(toJson(data: latestSharing))
// }
// } else {
// latestSharing = [SharingFile.init(value: url.absoluteString, thumbnail: nil, duration: nil, type: SharingFileType.text)]
//
// if(setInitialData) {
// initialSharing = latestSharing
// }
// eventSinkMedia?(latestSharing)
// }
// return true
// }
// latestSharing = nil
// return false
// }
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
if (arguments as! String? == "sharing" || arguments as! String? == "text" ) {
eventSinkMedia = events;
} else {
return FlutterError.init(code: "NO_SUCH_ARGUMENT", message: "No such argument\(String(describing: arguments))", details: nil);
}
return nil;
}
public func onCancel(withArguments arguments: Any?) -> FlutterError? {
if (arguments as! String? == "sharing" || arguments as! String? == "text" ) {
eventSinkMedia = nil;
} else {
return FlutterError.init(code: "NO_SUCH_ARGUMENT", message: "No such argument as \(String(describing: arguments))", details: nil);
}
return nil;
}
private func getAbsolutePath(for identifier: String?) -> String? {
guard let identifier else {
return nil
}
if (identifier.starts(with: "file://") || identifier.starts(with: "/var/mobile/Media") || identifier.starts(with: "/private/var/mobile")) {
return identifier.replacingOccurrences(of: "file://", with: "")
}
guard let phAsset = PHAsset.fetchAssets(
withLocalIdentifiers: [identifier],
options: .none).firstObject else {
return nil
}
let (url, _) = getFullSizeImageURLAndOrientation(for: phAsset)
return url
}
private func getFullSizeImageURLAndOrientation(for asset: PHAsset)-> (String?, Int) {
var url: String? = nil
var orientation: Int = 0
let semaphore = DispatchSemaphore(value: 0)
let options2 = PHContentEditingInputRequestOptions()
options2.isNetworkAccessAllowed = true
asset.requestContentEditingInput(with: options2){(input, info) in
orientation = Int(input?.fullSizeImageOrientation ?? 0)
url = input?.fullSizeImageURL?.path
semaphore.signal()
}
semaphore.wait()
return (url, orientation)
}
private func decode(data: Data) -> [SharingFile] {
do {
let encodedData = try JSONDecoder().decode([SharingFile].self, from: data)
return encodedData
} catch {
print("Decoding error:", error.localizedDescription)
return []
}
}
private func toJson(data: [SharingFile]?) -> String? {
if data == nil {
return nil
}
do {
let encodedData = try JSONEncoder().encode(data)
let json = String(data: encodedData, encoding: .utf8)!
return json
} catch {
fatalError(error.localizedDescription)
}
}
}

View file

@ -0,0 +1,8 @@
platform :ios, '12.0'
target 'Runner' do
# ... existing pods
# Add the pod for the external library
pod 'Evergage', '1.4.0'
end

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!--
PrivacyInfo.xcprivacy
Pods
Created by Bhagat on 18/05/24.
Copyright (c) 2024 ___ORGANIZATIONNAME___. All rights reserved.
-->
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<!-- <dict>-->
<!-- <key>NSPrivacyAccessedAPIType</key>-->
<!-- <string>NSPrivacyAccessedAPICategoryDiskSpace</string>-->
<!-- <key>NSPrivacyAccessedAPITypeReasons</key>-->
<!-- <array>-->
<!-- <string>E174.1</string>-->
<!-- </array>-->
<!-- </dict>-->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>1C8F.1</string>
</array>
</dict>
<!-- <dict>-->
<!-- <key>NSPrivacyAccessedAPIType</key>-->
<!-- <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>-->
<!-- <key>NSPrivacyAccessedAPITypeReasons</key>-->
<!-- <array>-->
<!-- <string>C617.1</string>-->
<!-- <string>0A2A.1</string>-->
<!-- </array>-->
<!-- </dict>-->
<!-- <dict>-->
<!-- <key>NSPrivacyAccessedAPIType</key>-->
<!-- <string>NSPrivacyAccessedAPICategorySystemBootTime</string>-->
<!-- <key>NSPrivacyAccessedAPITypeReasons</key>-->
<!-- <array>-->
<!-- <string>8FFB.1</string>-->
<!-- </array>-->
<!-- </dict>-->
</array>
</dict>
</plist>

View file

@ -0,0 +1,35 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint flutter_sharing_intent.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'flutter_sharing_intent'
s.version = '1.0.1'
s.summary = 'Sharing intent plugin for Flutter.'
s.description = <<-DESC
A Flutter plugin to receive sharing data in iOS and Android.
DESC
s.homepage = 'https://www.techind.co/'
s.license = { :file => '../LICENSE' }
s.author = { 'techind' => 'techind@gmail.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.platform = :ios, '12.0'
# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
'BUILD_LIBRARY_FOR_DISTRIBUTION' => 'YES'
# 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386'
}
s.static_framework = true
# Add resource bundle for Apple manifest policy
s.resource_bundle = {
'MySDKPrivacy' => ['Resources/PrivacyInfo.xcprivacy']
}
s.swift_version = '5.0'
end

View file

@ -0,0 +1,68 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:flutter_sharing_intent/model/sharing_file.dart';
import 'flutter_sharing_intent_platform_interface.dart';
class FlutterSharingIntent {
static FlutterSharingIntent instance = FlutterSharingIntent._();
factory FlutterSharingIntent() => instance;
late EventChannel _eChannelMedia;
Stream<List<SharedFile>>? _streamMedia;
FlutterSharingIntent._() {
_eChannelMedia =
const EventChannel("flutter_sharing_intent/events-sharing");
}
Future<String?> getPlatformVersion() {
return FlutterSharingIntentPlatform.instance.getPlatformVersion();
}
/// Returns a [Future], which completes to one of the following:
/// NOTE. The returned media on iOS (iOS ONLY) is already copied to a temp folder.
/// So, you need to delete the file after you finish using it
Future<List<SharedFile>> getInitialSharing() {
return FlutterSharingIntentPlatform.instance.getInitialSharing();
}
/// Call this method if you already consumed the callback
/// and don't want the same callback again
void reset() {
return FlutterSharingIntentPlatform.instance.reset();
}
/// Sets up a broadcast stream for receiving incoming media share change events.
///
/// Returns a broadcast [Stream] which emits events to listeners as follows:
/// Errors occurring during stream activation or deactivation are reported
/// through the `FlutterError` facility. Stream activation happens only when
/// stream listener count changes from 0 to 1. Stream deactivation happens
/// only when stream listener count changes from 1 to 0.
///
/// If the app was started by a link intent or user activity the stream will
/// not emit that initial one - query either the `getInitialMedia` instead.
Stream<List<SharedFile>> getMediaStream() {
if (_streamMedia == null) {
final stream =
_eChannelMedia.receiveBroadcastStream("sharing").cast<String?>();
_streamMedia = stream.transform<List<SharedFile>>(
StreamTransformer<String?, List<SharedFile>>.fromHandlers(
handleData: (String? data, EventSink<List<SharedFile>> sink) {
if (data == null) {
sink.add([]);
} else {
final encoded = jsonDecode(data);
sink.add(encoded
.map<SharedFile>((file) => SharedFile.fromJson(file))
.toList());
}
},
),
);
}
return _streamMedia!;
}
}

View file

@ -0,0 +1,36 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_sharing_intent/model/sharing_file.dart';
import 'flutter_sharing_intent_platform_interface.dart';
/// An implementation of [FlutterSharingIntentPlatform] that uses method channels.
class MethodChannelFlutterSharingIntent extends FlutterSharingIntentPlatform {
/// The method channel used to interact with the native platform.
@visibleForTesting
final methodChannel = const MethodChannel('flutter_sharing_intent');
@override
Future<String?> getPlatformVersion() async {
final version =
await methodChannel.invokeMethod<String>('getPlatformVersion');
return version;
}
@override
void reset() {
methodChannel.invokeMethod('reset');
}
@override
Future<List<SharedFile>> getInitialSharing() async {
final json = await methodChannel.invokeMethod('getInitialSharing');
if (json == null) return [];
final encoded = jsonDecode(json);
return encoded
.map<SharedFile>((file) => SharedFile.fromJson(file))
.toList();
}
}

View file

@ -0,0 +1,39 @@
import 'package:flutter_sharing_intent/model/sharing_file.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'flutter_sharing_intent_method_channel.dart';
abstract class FlutterSharingIntentPlatform extends PlatformInterface {
/// Constructs a FlutterSharingIntentPlatform.
FlutterSharingIntentPlatform() : super(token: _token);
static final Object _token = Object();
static FlutterSharingIntentPlatform _instance =
MethodChannelFlutterSharingIntent();
/// The default instance of [FlutterSharingIntentPlatform] to use.
///
/// Defaults to [MethodChannelFlutterSharingIntent].
static FlutterSharingIntentPlatform get instance => _instance;
/// Platform-specific implementations should set this with their own
/// platform-specific class that extends [FlutterSharingIntentPlatform] when
/// they register themselves.
static set instance(FlutterSharingIntentPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
Future<String?> getPlatformVersion() {
throw UnimplementedError('platformVersion() has not been implemented.');
}
Future<List<SharedFile>> getInitialSharing() async {
throw UnimplementedError('getInitialSharing() has not been implemented.');
}
void reset() async {
throw UnimplementedError('reset() has not been implemented.');
}
}

View file

@ -0,0 +1,59 @@
// ignore_for_file: constant_identifier_names
class SharedFile {
/// Image or Video path or text
/// NOTE. for iOS only the file is always copied
String? value;
/// Video thumbnail
String? thumbnail;
/// Video duration in milliseconds
int? duration;
/// Whether its a video or image or file
SharedMediaType type = SharedMediaType.OTHER;
/// Mime type of the file.
/// i.e. image/jpeg, video/mp4, text/plain
final String? mimeType;
/// Post message iOS ONLY
final String? message;
SharedFile(
{required this.value,
this.thumbnail,
this.duration,
this.type = SharedMediaType.OTHER,
this.mimeType,
this.message});
SharedFile.fromJson(Map<String, dynamic> json)
: value = json['value'] ?? json['path'],
thumbnail = json['thumbnail'],
duration = json['duration'],
type = json['type'] is int
? SharedMediaType.values[json['type']]
: SharedMediaType.OTHER,
mimeType = json['mimeType'],
message = json['message'];
Map<String, dynamic> toMap() {
return {
'value': value,
'thumbnail': thumbnail,
'duration': duration,
'type': type.index,
'mimeType': mimeType,
'message': message,
};
}
@override
String toString() {
return "{ value:$value, thumbnail:$thumbnail, duration:$duration, type:$type, mimeType:$mimeType, message:$message }";
}
}
enum SharedMediaType { TEXT, URL, IMAGE, VIDEO, FILE, WEB_SEARCH, OTHER }

View file

@ -0,0 +1,43 @@
name: flutter_sharing_intent
description: A flutter plugin that allow flutter apps to receive photos, videos, text, urls or any other file types from another app.
version: 2.0.4
homepage: https://github.com/bhagat-techind/flutter_sharing_intent
environment:
# sdk: '>=3.0.5 <4.0.0'
sdk: ">=3.1.2 <4.0.0"
flutter: ">=3.3.0"
dependencies:
flutter:
sdk: flutter
plugin_platform_interface: ^2.1.8
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^6.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# This section identifies this Flutter project as a plugin project.
# The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.)
# which should be registered in the plugin registry. This is required for
# using method channels.
# The Android 'package' specifies package in which the registered class is.
# This is required for using method channels on Android.
# The 'ffiPlugin' specifies that native code should be built and bundled.
# This is required for using `dart:ffi`.
# All these are used by the tooling to maintain consistency when
# adding or updating assets for this project.
plugin:
platforms:
android:
package: com.techind.flutter_sharing_intent
pluginClass: FlutterSharingIntentPlugin
ios:
pluginClass: FlutterSharingIntentPlugin

View file

@ -0,0 +1,27 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_sharing_intent/flutter_sharing_intent_method_channel.dart';
void main() {
MethodChannelFlutterSharingIntent platform =
MethodChannelFlutterSharingIntent();
const MethodChannel channel = MethodChannel('flutter_sharing_intent');
TestWidgetsFlutterBinding.ensureInitialized();
setUp(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, (MethodCall methodCall) async {
return '42';
});
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, null);
});
test('getPlatformVersion', () async {
expect(await platform.getPlatformVersion(), '42');
});
}

View file

@ -0,0 +1,45 @@
import 'package:flutter_sharing_intent/model/sharing_file.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_sharing_intent/flutter_sharing_intent.dart';
import 'package:flutter_sharing_intent/flutter_sharing_intent_platform_interface.dart';
import 'package:flutter_sharing_intent/flutter_sharing_intent_method_channel.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
class MockFlutterSharingIntentPlatform
with MockPlatformInterfaceMixin
implements FlutterSharingIntentPlatform {
@override
Future<String?> getPlatformVersion() => Future.value('42');
@override
Future<List<SharedFile>> getInitialSharing() {
return Future.value(
[SharedFile(value: "Test", type: SharedMediaType.TEXT)]);
}
@override
void reset() {}
}
void main() {
final FlutterSharingIntentPlatform initialPlatform =
FlutterSharingIntentPlatform.instance;
test('$MethodChannelFlutterSharingIntent is the default instance', () {
expect(initialPlatform, isInstanceOf<MethodChannelFlutterSharingIntent>());
});
FlutterSharingIntent flutterSharingIntentPlugin = FlutterSharingIntent();
MockFlutterSharingIntentPlatform fakePlatform =
MockFlutterSharingIntentPlatform();
FlutterSharingIntentPlatform.instance = fakePlatform;
test('getPlatformVersion', () async {
expect(await flutterSharingIntentPlugin.getPlatformVersion(), '42');
});
test('getInitialSharing', () async {
var sharingData = await flutterSharingIntentPlugin.getInitialSharing();
expect(sharingData.first.value, 'Test');
});
}

View file

@ -1,413 +0,0 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "5b7468c326d2f8a4f630056404ca0d291ade42918f4a3c6233618e724f39da8e"
url: "https://pub.dev"
source: hosted
version: "92.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "70e4b1ef8003c64793a9e268a551a82869a8a96f39deb73dea28084b0e8bf75e"
url: "https://pub.dev"
source: hosted
version: "9.0.0"
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async:
dependency: transitive
description:
name: async
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted
version: "2.13.0"
base32:
dependency: "direct dev"
description:
name: base32
sha256: "37548444aaee8bd5e91db442ce69ee3a79d3652ed47c1fa7568aa3bb9af0aea5"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
base_codecs:
dependency: "direct dev"
description:
name: base_codecs
sha256: "41701a12ede9912663decd708279924ece5018566daa7d1f484d5f4f10894f91"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
benchmark_harness:
dependency: "direct dev"
description:
name: benchmark_harness
sha256: a2d3c4c83cac0126bf38e41eaf7bd9ed4f6635f1ee1a0cbc6f79fa9736c62cbd
url: "https://pub.dev"
source: hosted
version: "2.4.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
cli_config:
dependency: transitive
description:
name: cli_config
sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
url: "https://pub.dev"
source: hosted
version: "0.2.0"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
convert:
dependency: transitive
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev"
source: hosted
version: "3.1.2"
coverage:
dependency: transitive
description:
name: coverage
sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d"
url: "https://pub.dev"
source: hosted
version: "1.15.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
url: "https://pub.dev"
source: hosted
version: "3.0.7"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev"
source: hosted
version: "4.0.0"
glob:
dependency: transitive
description:
name: glob
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.3"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
io:
dependency: transitive
description:
name: io
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.5"
lints:
dependency: "direct dev"
description:
name: lints
sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c
url: "https://pub.dev"
source: hosted
version: "1.0.1"
logging:
dependency: transitive
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev"
source: hosted
version: "1.3.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
url: "https://pub.dev"
source: hosted
version: "0.12.18"
meta:
dependency: transitive
description:
name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
source: hosted
version: "1.17.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
package_config:
dependency: transitive
description:
name: package_config
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
url: "https://pub.dev"
source: hosted
version: "2.2.0"
path:
dependency: transitive
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
pool:
dependency: transitive
description:
name: pool
sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
url: "https://pub.dev"
source: hosted
version: "1.5.2"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
shelf:
dependency: transitive
description:
name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.2"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
url: "https://pub.dev"
source: hosted
version: "1.1.3"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
url: "https://pub.dev"
source: hosted
version: "2.1.2"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812"
url: "https://pub.dev"
source: hosted
version: "0.10.13"
source_span:
dependency: transitive
description:
name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
test:
dependency: "direct dev"
description:
name: test
sha256: "77cc98ea27006c84e71a7356cf3daf9ddbde2d91d84f77dbfe64cf0e4d9611ae"
url: "https://pub.dev"
source: hosted
version: "1.28.0"
test_api:
dependency: transitive
description:
name: test_api
sha256: "19a78f63e83d3a61f00826d09bc2f60e191bf3504183c001262be6ac75589fb8"
url: "https://pub.dev"
source: hosted
version: "0.7.8"
test_core:
dependency: transitive
description:
name: test_core
sha256: f1072617a6657e5fc09662e721307f7fb009b4ed89b19f47175d11d5254a62d4
url: "https://pub.dev"
source: hosted
version: "0.6.14"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
url: "https://pub.dev"
source: hosted
version: "15.0.2"
watcher:
dependency: transitive
description:
name: watcher
sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a"
url: "https://pub.dev"
source: hosted
version: "1.1.4"
web:
dependency: transitive
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
url: "https://pub.dev"
source: hosted
version: "3.0.3"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
yaml:
dependency: transitive
description:
name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.10.0 <4.0.0"

View file

@ -1,357 +0,0 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "5b7468c326d2f8a4f630056404ca0d291ade42918f4a3c6233618e724f39da8e"
url: "https://pub.dev"
source: hosted
version: "92.0.0"
analyzer:
dependency: "direct dev"
description:
name: analyzer
sha256: "70e4b1ef8003c64793a9e268a551a82869a8a96f39deb73dea28084b0e8bf75e"
url: "https://pub.dev"
source: hosted
version: "9.0.0"
archive:
dependency: "direct main"
description:
name: archive
sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd"
url: "https://pub.dev"
source: hosted
version: "4.0.7"
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async:
dependency: transitive
description:
name: async
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted
version: "2.13.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
characters:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.4.0"
clock:
dependency: transitive
description:
name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted
version: "1.1.2"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
convert:
dependency: transitive
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev"
source: hosted
version: "3.1.2"
crypto:
dependency: transitive
description:
name: crypto
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
url: "https://pub.dev"
source: hosted
version: "3.0.7"
dart_style:
dependency: "direct dev"
description:
name: dart_style
sha256: a9c30492da18ff84efe2422ba2d319a89942d93e58eb0b73d32abe822ef54b7b
url: "https://pub.dev"
source: hosted
version: "3.1.3"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted
version: "1.3.3"
ffi:
dependency: transitive
description:
name: ffi
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
glob:
dependency: transitive
description:
name: glob
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.3"
http:
dependency: "direct main"
description:
name: http
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
url: "https://pub.dev"
source: hosted
version: "1.6.0"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.dev"
source: hosted
version: "11.0.2"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev"
source: hosted
version: "3.0.10"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
lints:
dependency: transitive
description:
name: lints
sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0
url: "https://pub.dev"
source: hosted
version: "6.0.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
source: hosted
version: "1.17.0"
package_config:
dependency: transitive
description:
name: package_config
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
url: "https://pub.dev"
source: hosted
version: "2.2.0"
path:
dependency: "direct main"
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
posix:
dependency: transitive
description:
name: posix
sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61"
url: "https://pub.dev"
source: hosted
version: "6.0.3"
pub_semver:
dependency: "direct dev"
description:
name: pub_semver
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
source_span:
dependency: transitive
description:
name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
test_api:
dependency: transitive
description:
name: test_api
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
url: "https://pub.dev"
source: hosted
version: "0.7.7"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vector_math:
dependency: "direct main"
description:
name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev"
source: hosted
version: "2.2.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
url: "https://pub.dev"
source: hosted
version: "15.0.2"
watcher:
dependency: transitive
description:
name: watcher
sha256: f52385d4f73589977c80797e60fe51014f7f2b957b5e9a62c3f6ada439889249
url: "https://pub.dev"
source: hosted
version: "1.2.0"
web:
dependency: transitive
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
yaml:
dependency: "direct dev"
description:
name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.9.0 <4.0.0"
flutter: ">=3.35.0"

View file

@ -1,493 +0,0 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
url: "https://pub.dev"
source: hosted
version: "67.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
url: "https://pub.dev"
source: hosted
version: "6.4.1"
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async:
dependency: transitive
description:
name: async
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted
version: "2.13.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f"
url: "https://pub.dev"
source: hosted
version: "2.0.4"
cli_config:
dependency: transitive
description:
name: cli_config
sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
url: "https://pub.dev"
source: hosted
version: "0.2.0"
cli_util:
dependency: transitive
description:
name: cli_util
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
url: "https://pub.dev"
source: hosted
version: "0.4.2"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
convert:
dependency: transitive
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev"
source: hosted
version: "3.1.2"
coverage:
dependency: transitive
description:
name: coverage
sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d"
url: "https://pub.dev"
source: hosted
version: "1.15.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
url: "https://pub.dev"
source: hosted
version: "3.0.7"
csslib:
dependency: transitive
description:
name: csslib
sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev"
source: hosted
version: "4.0.0"
glob:
dependency: transitive
description:
name: glob
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.3"
html:
dependency: transitive
description:
name: html
sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602"
url: "https://pub.dev"
source: hosted
version: "0.15.6"
http:
dependency: transitive
description:
name: http
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
url: "https://pub.dev"
source: hosted
version: "1.6.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
io:
dependency: transitive
description:
name: io
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.5"
js:
dependency: transitive
description:
name: js
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
json_annotation:
dependency: transitive
description:
name: json_annotation
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
url: "https://pub.dev"
source: hosted
version: "4.9.0"
lints:
dependency: "direct dev"
description:
name: lints
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
logging:
dependency: transitive
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev"
source: hosted
version: "1.3.0"
markdown:
dependency: transitive
description:
name: markdown
sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1"
url: "https://pub.dev"
source: hosted
version: "7.3.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.17"
meta:
dependency: transitive
description:
name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
source: hosted
version: "1.17.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
package_config:
dependency: transitive
description:
name: package_config
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
url: "https://pub.dev"
source: hosted
version: "2.2.0"
pana:
dependency: "direct dev"
description:
name: pana
sha256: "6f4372d5d2af5fe3fc6491c18f575601743bceb8433c7f179a6fffd162ee55f1"
url: "https://pub.dev"
source: hosted
version: "0.21.39"
path:
dependency: transitive
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
pool:
dependency: transitive
description:
name: pool
sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
url: "https://pub.dev"
source: hosted
version: "1.5.2"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
url: "https://pub.dev"
source: hosted
version: "1.5.0"
retry:
dependency: transitive
description:
name: retry
sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
safe_url_check:
dependency: transitive
description:
name: safe_url_check
sha256: "49a3e060a7869cbafc8f4845ca1ecbbaaa53179980a32f4fdfeab1607e90f41d"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
shelf:
dependency: transitive
description:
name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.2"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
url: "https://pub.dev"
source: hosted
version: "1.1.3"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
url: "https://pub.dev"
source: hosted
version: "2.1.2"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812"
url: "https://pub.dev"
source: hosted
version: "0.10.13"
source_span:
dependency: transitive
description:
name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
tar:
dependency: transitive
description:
name: tar
sha256: "22f67e2d77b51050436620b2a5de521c58ca6f0b75af1d9ab3c8cae2eae58fcd"
url: "https://pub.dev"
source: hosted
version: "1.0.5"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
test:
dependency: "direct dev"
description:
name: test
sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7"
url: "https://pub.dev"
source: hosted
version: "1.26.3"
test_api:
dependency: transitive
description:
name: test_api
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
url: "https://pub.dev"
source: hosted
version: "0.7.7"
test_core:
dependency: transitive
description:
name: test_core
sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0"
url: "https://pub.dev"
source: hosted
version: "0.6.12"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
url: "https://pub.dev"
source: hosted
version: "15.0.2"
watcher:
dependency: transitive
description:
name: watcher
sha256: f52385d4f73589977c80797e60fe51014f7f2b957b5e9a62c3f6ada439889249
url: "https://pub.dev"
source: hosted
version: "1.2.0"
web:
dependency: transitive
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
url: "https://pub.dev"
source: hosted
version: "3.0.3"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
yaml:
dependency: transitive
description:
name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.8.0 <4.0.0"

View file

@ -1,469 +0,0 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d
url: "https://pub.dev"
source: hosted
version: "91.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: f51c8499b35f9b26820cfe914828a6a98a94efd5cc78b37bb7d03debae3a1d08
url: "https://pub.dev"
source: hosted
version: "8.4.1"
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async:
dependency: transitive
description:
name: async
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted
version: "2.13.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
characters:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.4.0"
cli_config:
dependency: transitive
description:
name: cli_config
sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
url: "https://pub.dev"
source: hosted
version: "0.2.0"
clock:
dependency: transitive
description:
name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted
version: "1.1.2"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
convert:
dependency: transitive
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev"
source: hosted
version: "3.1.2"
coverage:
dependency: transitive
description:
name: coverage
sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d"
url: "https://pub.dev"
source: hosted
version: "1.15.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
url: "https://pub.dev"
source: hosted
version: "3.0.7"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted
version: "1.3.3"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev"
source: hosted
version: "4.0.0"
glob:
dependency: transitive
description:
name: glob
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.3"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
io:
dependency: transitive
description:
name: io
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.5"
js:
dependency: transitive
description:
name: js
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.dev"
source: hosted
version: "11.0.2"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev"
source: hosted
version: "3.0.10"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
logging:
dependency: transitive
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev"
source: hosted
version: "1.3.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
source: hosted
version: "1.17.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
package_config:
dependency: transitive
description:
name: package_config
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
url: "https://pub.dev"
source: hosted
version: "2.2.0"
path:
dependency: transitive
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
pool:
dependency: transitive
description:
name: pool
sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
url: "https://pub.dev"
source: hosted
version: "1.5.2"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
shelf:
dependency: transitive
description:
name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.2"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
url: "https://pub.dev"
source: hosted
version: "1.1.3"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
url: "https://pub.dev"
source: hosted
version: "2.1.2"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812"
url: "https://pub.dev"
source: hosted
version: "0.10.13"
source_span:
dependency: transitive
description:
name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
test:
dependency: "direct dev"
description:
name: test
sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7"
url: "https://pub.dev"
source: hosted
version: "1.26.3"
test_api:
dependency: transitive
description:
name: test_api
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
url: "https://pub.dev"
source: hosted
version: "0.7.7"
test_core:
dependency: transitive
description:
name: test_core
sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0"
url: "https://pub.dev"
source: hosted
version: "0.6.12"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev"
source: hosted
version: "2.2.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
url: "https://pub.dev"
source: hosted
version: "15.0.2"
watcher:
dependency: transitive
description:
name: watcher
sha256: f52385d4f73589977c80797e60fe51014f7f2b957b5e9a62c3f6ada439889249
url: "https://pub.dev"
source: hosted
version: "1.2.0"
web:
dependency: transitive
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
url: "https://pub.dev"
source: hosted
version: "3.0.3"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
yaml:
dependency: transitive
description:
name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.9.0 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"

View file

@ -5,6 +5,8 @@ dependency_overrides:
path: ./dependencies/dots_indicator
ed25519_edwards:
path: ./dependencies/ed25519_edwards
flutter_sharing_intent:
path: ./dependencies/flutter_sharing_intent
hand_signature:
path: ./dependencies/hand_signature
hashlib:

View file

@ -1,197 +0,0 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
async:
dependency: transitive
description:
name: async
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted
version: "2.13.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
characters:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.4.0"
clock:
dependency: transitive
description:
name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted
version: "1.1.2"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted
version: "1.3.3"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.dev"
source: hosted
version: "11.0.2"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev"
source: hosted
version: "3.0.10"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
matcher:
dependency: transitive
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
source: hosted
version: "1.17.0"
path:
dependency: transitive
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
qr:
dependency: "direct main"
description:
name: qr
sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
source_span:
dependency: transitive
description:
name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
test_api:
dependency: transitive
description:
name: test_api
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
url: "https://pub.dev"
source: hosted
version: "0.7.7"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev"
source: hosted
version: "2.2.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
url: "https://pub.dev"
source: hosted
version: "15.0.2"
sdks:
dart: ">=3.8.0-0 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"

View file

@ -42,7 +42,7 @@ def integrate_package(folder_name, data):
global config_lock
repo_url = data['git']
keep_list = ["lib", "test", "LICENSE", "pubspec.yaml"]
keep_list = ["lib", "test", "LICENSE", "pubspec.yaml", "android", "ios"]
if "keep" in data:
keep_list += [item.rstrip('/') for item in data['keep']]