{"id":4898,"date":"2021-07-07T11:19:07","date_gmt":"2021-07-07T09:19:07","guid":{"rendered":"https:\/\/www.evertop.pl\/?p=4898"},"modified":"2021-07-07T11:35:15","modified_gmt":"2021-07-07T09:35:15","slug":"mediastore-in-flutter","status":"publish","type":"post","link":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/","title":{"rendered":"MediaStore in Flutter"},"content":{"rendered":"<p>Using platform channels to provide access to MediaStore API from Dart.<\/p>\n<p>&nbsp;<\/p>\n<h2>Intro<\/h2>\n<p>This article will guide you through the process of creating a simple flutter app that allows you to draw on a canvas. Then we will add the ability for this app to save those images to external storage volume using\u00a0<a href=\"https:\/\/developer.android.com\/reference\/android\/provider\/MediaStore\" target=\"_blank\" rel=\"noopener noreferrer\">MediaStore API<\/a>\u00a0which allows to retrieve and update media files. Files saved this way are discoverable e.g. by system file explorer and will survive in case your app gets uninstalled. MediaStore API was added in API level 1 which makes it available in all Android devices!<\/p>\n<p>To use this API we will need to implement a portion of code both in the host platform (in this case Android) and in Dart using a mechanism called\u00a0<a href=\"https:\/\/flutter.dev\/docs\/development\/platform-integration\/platform-channels\" target=\"_blank\" rel=\"noopener noreferrer\">Platform Channels<\/a>.<\/p>\n<p><img loading=\"lazy\" class=\"alignnone wp-image-4900 size-large\" src=\"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-16-1024x530.jpg\" alt=\"mobile\" width=\"640\" height=\"331\" srcset=\"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-16-1024x530.jpg 1024w, https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-16-300x155.jpg 300w, https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-16-768x398.jpg 768w, https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-16.jpg 1282w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/p>\n<h2>App for drawing a masterpiece on canvas<\/h2>\n<p>As a first step, we will create the aforementioned Flutter app, allowing users to create simple drawings. It will contain two button controls, one for picking the colour of the paintbrush and the second for clearing the canvas. Of course, the rest of the space will be devoted to the canvas, which will allow user to draw by pressing and moving a finger.<\/p>\n<p>To track user\u2019s gestures, we will use GestureDetector widget, which provides access to\u00a0<em>onPanDown\/Update\/Cancel\/End<\/em>\u00a0callbacks. Each track traversed by a finger will be recorded using\u00a0<em>Path\u00a0<\/em>class from\u00a0<em>dart:ui<\/em>. We will store all tracks with their colours as a list in state class to be able to perform drawing and display the graphic.<\/p>\n<p>To draw to the canvas directly, we will take advantage of\u00a0<em>CustomPainter,\u00a0<\/em>to which all the tracks with their colours will be provided.<\/p>\n<p>Tapping on the change colour button will open the dialogue with\u00a0<em>ColorPicker\u00a0<\/em>from\u00a0<a href=\"https:\/\/pub.dev\/packages\/flutter_colorpicker\" target=\"_blank\" rel=\"noopener noreferrer\"><em>flutter_colorpicker<\/em><\/a><em>\u00a0<\/em>library (using version 0.4.0). It will allow user to change colour while diving deeper into the masterpiece.<\/p>\n<p>As the main topic of this article is related to platform channels, I will not go into further details regarding the implementation but only leave a link to the repo containing the work done until this point:\u00a0<a href=\"https:\/\/github.com\/Dartek12\/flutter_media_store\/tree\/step_1\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/github.com\/Dartek12\/flutter_media_store\/tree\/step_1<\/a>.<\/p>\n<figure style=\"width: 700px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" src=\"https:\/\/miro.medium.com\/max\/700\/1*1vHCPZXEe3w3alI0Yo5CMA.png\" alt=\"Our tiny graphical Flutter editor\" width=\"700\" height=\"1400\" \/><figcaption class=\"wp-caption-text\">Our tiny graphical Flutter editor<\/figcaption><\/figure>\n<p>&nbsp;<\/p>\n<h2>Calling system API from Dart<\/h2>\n<p>Whenever you want to use platform-specific code which was not provided with the Flutter framework or third-party plugin provider, you will have to turn to\u00a0<strong>platform channels<\/strong>. It is a system that allows executing Java\/Kotlin on Android or Objective-C\/Swift on iOS, which relies on passing messages to the hosting platform. Communication is done in an asynchronous manner so that your user interface stays responsive.<\/p>\n<p>To send a message to the hosting platform, you will need to create an instance of\u00a0<em>MethodChannel<\/em>\u00a0in dart code, passing its name to the constructor. In corresponding native code, you will also have to register\u00a0<em>MethodChannel<\/em>\u00a0on Android and\u00a0<em>FlutterMethodChannel\u00a0<\/em>on iOS using the same name.<\/p>\n<p>Then you send a message at the Dart side calling\u00a0<em>invokeMethod\u00a0<\/em>with the method name and the list of arguments of\u00a0<a href=\"https:\/\/flutter.dev\/docs\/development\/platform-integration\/platform-channels#codec\" target=\"_blank\" rel=\"noopener noreferrer\">supported types<\/a>\u00a0and use registered handler at host platform side to handle the message (including calling native APIs) and produce the result.<\/p>\n<p>That was quite a general description, but no worries \u2014 examples are coming!<\/p>\n<p><img loading=\"lazy\" class=\"alignnone wp-image-4901 size-large\" src=\"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-17-1024x530.jpg\" alt=\"two people are programming\" width=\"640\" height=\"331\" srcset=\"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-17-1024x530.jpg 1024w, https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-17-300x155.jpg 300w, https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-17-768x398.jpg 768w, https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-17.jpg 1282w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/p>\n<h2>How are we going to use MediaStore?<\/h2>\n<p>The journey from our canvas to saving a file to the MediaStore will consist of few steps:<\/p>\n<ul>\n<li>saving canvas contents to a temporary file,<\/li>\n<li>passing file path to method channel,<\/li>\n<li>handle a file on the Android side by adding it to the MediaStore collection.<\/li>\n<\/ul>\n<p>That\u2019s it. Let\u2019s get started!<\/p>\n<h3>Step 1. Saving canvas contents to temporary media file.<\/h3>\n<p>Using\u00a0<em>PictureRecorder\u00a0<\/em>object we will record everything we do to the canvas so that we can save operations result to the file. We assign global key to the container widget holding the canvas to read its size. Having all of that the next step is to save it to temporary PNG file with the help of\u00a0<a href=\"https:\/\/pub.dev\/packages\/path_provider\" target=\"_blank\" rel=\"noopener noreferrer\"><em>path_provider<\/em><\/a>,\u00a0<a href=\"https:\/\/pub.dev\/packages\/path\" target=\"_blank\" rel=\"noopener noreferrer\"><em>path<\/em>\u00a0<\/a>and\u00a0<a href=\"https:\/\/pub.dev\/packages\/uuid\" target=\"_blank\" rel=\"noopener noreferrer\"><em>uuid\u00a0<\/em><\/a>which are open source packages:<\/p>\n<pre class=\"ql-syntax\" spellcheck=\"false\">Future&lt;File&gt; _saveCanvasToTemporaryFile() async {\r\n  final recorder = PictureRecorder();\r\n  final RenderBox box = _containerKey.currentContext!.findRenderObject() as RenderBox;\r\n  final size = box.size;\r\n  final rect = Rect.fromLTRB(0, 0, size.width, size.height);\r\n  final canvas = Canvas(recorder, rect);\r\n  canvas.drawRect(rect, Paint()..color = Colors.white);\r\n  _drawOnCanvas(canvas, size: size, paint: _paint, paths: _paths);\r\n  final picture = recorder.endRecording();\r\n  final image = await picture.toImage(size.width.toInt(), size.height.toInt());\r\n  final bytes = await image.toByteData(format: ImageByteFormat.png);\r\n  final identifier = Uuid().v4();\r\n  final fileName = '$identifier.png';\r\n  final directory = await path_provider.getTemporaryDirectory();\r\n  final filePath = path.join(directory.path, fileName);\r\n  return await File(filePath).writeAsBytes(bytes!.buffer.asUint8List());\r\n}<\/pre>\n<h3>Step 2. Passing file path to method channel.<\/h3>\n<p>Let\u2019s create Dart class for encapsulating communication with the host platform containg single method for adding item with file path and name.<\/p>\n<pre class=\"ql-syntax\" spellcheck=\"false\">class MediaStore {\r\n  static const _channel = MethodChannel('flutter_media_store');\r\n\r\n  Future&lt;void&gt; addItem({required File file, required String name}) async {\r\n    await _channel.invokeMethod('addItem', {'path': file.path, 'name': name});\r\n  }\r\n}<\/pre>\n<p>It was that easy!<\/p>\n<h3>Step 3. Handling file at Android side.<\/h3>\n<p>Now comes the toughest part. We will add handlers at Android side of the app. We need to override\u00a0<em>configureFlutterEngine<\/em>\u00a0method in our host activity in order to register method channel:<\/p>\n<pre class=\"ql-syntax\" spellcheck=\"false\">override fun configureFlutterEngine(flutterEngine: FlutterEngine) {\r\n    super.configureFlutterEngine(flutterEngine)\r\n    MethodChannel(\r\n        flutterEngine.dartExecutor.binaryMessenger,\r\n        \"flutter_media_store\"\r\n    ).setMethodCallHandler { call, result -&gt;\r\n        when (call.method) {\r\n            \"addItem\" -&gt; {\r\n                addItem(call.argument(\"path\")!!, call.argument(\"name\")!!)\r\n                result.success(null)\r\n            }\r\n        }\r\n    }\r\n}<\/pre>\n<p>Now we are ready to implement\u00a0<em>addItem\u00a0<\/em>method. We will use\u00a0<em>content resolver\u00a0<\/em>object to insert content values into the appropriate media store volume, which in result returns URI.<\/p>\n<p>Then we will open output stream to that URI so that we can write contents to it (which will be copied from our temporaral storage created in Flutter).<\/p>\n<pre class=\"ql-syntax\" spellcheck=\"false\">private fun addItem(path: String, name: String) {\r\n    val extension = MimeTypeMap.getFileExtensionFromUrl(path)\r\n    val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)!!\r\n\r\n    val collection = if(Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.Q) {\r\n        MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)\r\n    } else {\r\n        MediaStore.Images.Media.EXTERNAL_CONTENT_URI\r\n    }\r\n\r\n    val values = ContentValues().apply {\r\n        put(MediaStore.Images.Media.DISPLAY_NAME, name)\r\n        put(MediaStore.Images.Media.MIME_TYPE, mimeType)\r\n        if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.Q) {\r\n            put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + getString(R.string.app_name))\r\n            put(MediaStore.Images.Media.IS_PENDING, 1)\r\n        }\r\n    }\r\n\r\n    val resolver = applicationContext.contentResolver\r\n    val uri = resolver.insert(collection, values)!!\r\n\r\n    try {\r\n        resolver.openOutputStream(uri).use { os -&gt;\r\n            File(path).inputStream().use { it.copyTo(os!!) }\r\n        }\r\n\r\n        if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.Q) {\r\n            values.clear()\r\n            values.put(MediaStore.Images.Media.IS_PENDING, 0)\r\n            resolver.update(uri, values, null, null)\r\n        }\r\n    } catch (ex: IOException) {\r\n        Log.e(\"MediaStore\", ex.message, ex)\r\n    }\r\n}<\/pre>\n<p><strong>Beware:\u00a0<\/strong>If<strong>\u00a0<\/strong>this is run on Android 9.0 or a lower device, then you will have to request permissions before saving a file to the MediaStore!<\/p>\n<h3>Last step<\/h3>\n<p>Finally we can connect everything. Add button control to the top bar which will invoke previously written code with an example implementation of:<\/p>\n<pre class=\"ql-syntax\" spellcheck=\"false\">void _saveImage() async {\r\n  File tempFile = await _saveCanvasToTemporaryFile();\r\n  await _saveFileToMediaStore(tempFile);\r\n  await tempFile.delete();\r\n  ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('File saved!')));\r\n}<\/pre>\n<h1><\/h1>\n<h2>Results<\/h2>\n<p>Now we can play a bit with our app and use save button to see if it&#8217;s working properly.<\/p>\n<figure style=\"width: 700px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" src=\"https:\/\/miro.medium.com\/max\/700\/1*5pK148KcXk9cIyCtDyNOmw.png\" alt=\"Our masterpiece\" width=\"700\" height=\"1400\" \/><figcaption class=\"wp-caption-text\">Our masterpiece<\/figcaption><\/figure>\n<p>&nbsp;<\/p>\n<figure style=\"width: 700px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" src=\"https:\/\/miro.medium.com\/max\/700\/1*JqLcfdPJBLgJOiSx8ZoAWg.png\" alt=\"Let\u2019s check the File Explorer and\u2026 Success!\" width=\"700\" height=\"1400\" \/><figcaption class=\"wp-caption-text\">Let\u2019s check the File Explorer and\u2026 Success!<\/figcaption><\/figure>\n<p>Success! We managed to draw a masterpiece and saved it in MediaStore!<\/p>\n<p>&nbsp;<\/p>\n<h2>Summary<\/h2>\n<p>In this article, we have created a simple Flutter app with extraordinary capabilities. We have learnt how to draw to the canvas, save it to the file and then insert it into MediaStore using the power of platform channels.<\/p>\n<p>As one could notice, for now our platform channel contains public interface for inserting only images and cannot save other types of media. That&#8217;s okay for us because it was our intent. But MediaStore is capable of adding media data like video or audio. We can pretty easily extend existing code by adding public interface for inserting those types of media and handling them at Android side to be able to reuse this piece of software in other Flutter apps.<\/p>\n<p>Although we managed all of it by ourselves this time, that does not have to be the case. You can always use\u00a0<a href=\"https:\/\/pub.dev\/packages\/pigeon\" target=\"_blank\" rel=\"noopener noreferrer\"><em>pigeon\u00a0<\/em><\/a>package, which allows you to generate automatically the code responsible for interaction between Flutter and Host Platform. And if you are interested in the internals and possible performance improvements of platform channels, I strongly recommend reading this great article:\u00a0<a href=\"https:\/\/medium.com\/flutter\/improving-platform-channel-performance-in-flutter-e5b4e5df04af\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/medium.com\/flutter\/improving-platform-channel-performance-in-flutter-e5b4e5df04af<\/a>.<\/p>\n<p>The final code can be found here:\u00a0<a href=\"https:\/\/github.com\/Dartek12\/flutter_media_store\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/github.com\/Dartek12\/flutter_media_store<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using platform channels to provide access to MediaStore API from Dart. &nbsp; Intro This article will guide you through the process of creating a simple flutter app that allows you to draw on a canvas. Then we will add the ability for this app to save those images to external storage volume using\u00a0MediaStore API\u00a0which allows [&hellip;]<\/p>\n","protected":false},"author":26,"featured_media":4899,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[13],"tags":[98,156,38],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v16.8 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>MediaStore in Flutter - Evertop<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"MediaStore in Flutter - Evertop\" \/>\n<meta property=\"og:description\" content=\"Using platform channels to provide access to MediaStore API from Dart. &nbsp; Intro This article will guide you through the process of creating a simple flutter app that allows you to draw on a canvas. Then we will add the ability for this app to save those images to external storage volume using\u00a0MediaStore API\u00a0which allows [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/\" \/>\n<meta property=\"og:site_name\" content=\"Evertop\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/EvertopPoland\/\" \/>\n<meta property=\"article:published_time\" content=\"2021-07-07T09:19:07+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-07-07T09:35:15+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-15.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1282\" \/>\n\t<meta property=\"og:image:height\" content=\"664\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Bartosz Biernacki\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.evertop.pl\/#organization\",\"name\":\"Evertop\",\"url\":\"https:\/\/www.evertop.pl\/\",\"sameAs\":[\"https:\/\/www.facebook.com\/EvertopPoland\/\",\"https:\/\/www.linkedin.com\/company\/evertop-software-development\/\"],\"logo\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.evertop.pl\/#logo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/04\/logo_new.png\",\"contentUrl\":\"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/04\/logo_new.png\",\"width\":582,\"height\":114,\"caption\":\"Evertop\"},\"image\":{\"@id\":\"https:\/\/www.evertop.pl\/#logo\"}},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.evertop.pl\/#website\",\"url\":\"https:\/\/www.evertop.pl\/\",\"name\":\"Evertop\",\"description\":\"we code the future\",\"publisher\":{\"@id\":\"https:\/\/www.evertop.pl\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.evertop.pl\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#primaryimage\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-15.png\",\"contentUrl\":\"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-15.png\",\"width\":1282,\"height\":664,\"caption\":\"mediastore-in-flutter\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#webpage\",\"url\":\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/\",\"name\":\"MediaStore in Flutter - Evertop\",\"isPartOf\":{\"@id\":\"https:\/\/www.evertop.pl\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#primaryimage\"},\"datePublished\":\"2021-07-07T09:19:07+00:00\",\"dateModified\":\"2021-07-07T09:35:15+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Strona g\\u0142\\u00f3wna\",\"item\":\"https:\/\/www.evertop.pl\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"MediaStore in Flutter\"}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#webpage\"},\"author\":{\"@id\":\"https:\/\/www.evertop.pl\/#\/schema\/person\/1ec1f9d1cd00169091d2e68a31f06761\"},\"headline\":\"MediaStore in Flutter\",\"datePublished\":\"2021-07-07T09:19:07+00:00\",\"dateModified\":\"2021-07-07T09:35:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#webpage\"},\"wordCount\":1117,\"publisher\":{\"@id\":\"https:\/\/www.evertop.pl\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-15.png\",\"keywords\":[\"flutter\",\"MediaStore\",\"mobile\"],\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.evertop.pl\/#\/schema\/person\/1ec1f9d1cd00169091d2e68a31f06761\",\"name\":\"Bartosz Biernacki\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.evertop.pl\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/0e17d7baa82cfbddb0805f8ab516e38b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/0e17d7baa82cfbddb0805f8ab516e38b?s=96&d=mm&r=g\",\"caption\":\"Bartosz Biernacki\"},\"url\":\"https:\/\/www.evertop.pl\/en\/author\/bbiernacki\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"MediaStore in Flutter - Evertop","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/","og_locale":"en_US","og_type":"article","og_title":"MediaStore in Flutter - Evertop","og_description":"Using platform channels to provide access to MediaStore API from Dart. &nbsp; Intro This article will guide you through the process of creating a simple flutter app that allows you to draw on a canvas. Then we will add the ability for this app to save those images to external storage volume using\u00a0MediaStore API\u00a0which allows [&hellip;]","og_url":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/","og_site_name":"Evertop","article_publisher":"https:\/\/www.facebook.com\/EvertopPoland\/","article_published_time":"2021-07-07T09:19:07+00:00","article_modified_time":"2021-07-07T09:35:15+00:00","og_image":[{"width":1282,"height":664,"url":"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-15.png","path":"\/home\/evertop\/web-evertop\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-15.png","size":"full","id":4899,"alt":"mediastore-in-flutter","pixels":851248,"type":"image\/png"}],"twitter_card":"summary_large_image","twitter_misc":{"Written by":"Bartosz Biernacki","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Organization","@id":"https:\/\/www.evertop.pl\/#organization","name":"Evertop","url":"https:\/\/www.evertop.pl\/","sameAs":["https:\/\/www.facebook.com\/EvertopPoland\/","https:\/\/www.linkedin.com\/company\/evertop-software-development\/"],"logo":{"@type":"ImageObject","@id":"https:\/\/www.evertop.pl\/#logo","inLanguage":"en-US","url":"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/04\/logo_new.png","contentUrl":"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/04\/logo_new.png","width":582,"height":114,"caption":"Evertop"},"image":{"@id":"https:\/\/www.evertop.pl\/#logo"}},{"@type":"WebSite","@id":"https:\/\/www.evertop.pl\/#website","url":"https:\/\/www.evertop.pl\/","name":"Evertop","description":"we code the future","publisher":{"@id":"https:\/\/www.evertop.pl\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.evertop.pl\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"ImageObject","@id":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#primaryimage","inLanguage":"en-US","url":"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-15.png","contentUrl":"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-15.png","width":1282,"height":664,"caption":"mediastore-in-flutter"},{"@type":"WebPage","@id":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#webpage","url":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/","name":"MediaStore in Flutter - Evertop","isPartOf":{"@id":"https:\/\/www.evertop.pl\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#primaryimage"},"datePublished":"2021-07-07T09:19:07+00:00","dateModified":"2021-07-07T09:35:15+00:00","breadcrumb":{"@id":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Strona g\u0142\u00f3wna","item":"https:\/\/www.evertop.pl\/en\/"},{"@type":"ListItem","position":2,"name":"MediaStore in Flutter"}]},{"@type":"Article","@id":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#article","isPartOf":{"@id":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#webpage"},"author":{"@id":"https:\/\/www.evertop.pl\/#\/schema\/person\/1ec1f9d1cd00169091d2e68a31f06761"},"headline":"MediaStore in Flutter","datePublished":"2021-07-07T09:19:07+00:00","dateModified":"2021-07-07T09:35:15+00:00","mainEntityOfPage":{"@id":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#webpage"},"wordCount":1117,"publisher":{"@id":"https:\/\/www.evertop.pl\/#organization"},"image":{"@id":"https:\/\/www.evertop.pl\/en\/mediastore-in-flutter\/#primaryimage"},"thumbnailUrl":"https:\/\/www.evertop.pl\/wp-content\/uploads\/2021\/07\/grafiki_blog_5_Obszar-roboczy-1-kopia-15.png","keywords":["flutter","MediaStore","mobile"],"articleSection":["Blog"],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.evertop.pl\/#\/schema\/person\/1ec1f9d1cd00169091d2e68a31f06761","name":"Bartosz Biernacki","image":{"@type":"ImageObject","@id":"https:\/\/www.evertop.pl\/#personlogo","inLanguage":"en-US","url":"https:\/\/secure.gravatar.com\/avatar\/0e17d7baa82cfbddb0805f8ab516e38b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0e17d7baa82cfbddb0805f8ab516e38b?s=96&d=mm&r=g","caption":"Bartosz Biernacki"},"url":"https:\/\/www.evertop.pl\/en\/author\/bbiernacki\/"}]}},"_links":{"self":[{"href":"https:\/\/www.evertop.pl\/en\/wp-json\/wp\/v2\/posts\/4898"}],"collection":[{"href":"https:\/\/www.evertop.pl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.evertop.pl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.evertop.pl\/en\/wp-json\/wp\/v2\/users\/26"}],"replies":[{"embeddable":true,"href":"https:\/\/www.evertop.pl\/en\/wp-json\/wp\/v2\/comments?post=4898"}],"version-history":[{"count":10,"href":"https:\/\/www.evertop.pl\/en\/wp-json\/wp\/v2\/posts\/4898\/revisions"}],"predecessor-version":[{"id":4915,"href":"https:\/\/www.evertop.pl\/en\/wp-json\/wp\/v2\/posts\/4898\/revisions\/4915"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.evertop.pl\/en\/wp-json\/wp\/v2\/media\/4899"}],"wp:attachment":[{"href":"https:\/\/www.evertop.pl\/en\/wp-json\/wp\/v2\/media?parent=4898"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.evertop.pl\/en\/wp-json\/wp\/v2\/categories?post=4898"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.evertop.pl\/en\/wp-json\/wp\/v2\/tags?post=4898"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}