{"id":22979,"date":"2022-01-13T11:15:15","date_gmt":"2022-01-13T11:15:15","guid":{"rendered":"https:\/\/www.bacancytechnology.com\/blog\/?p=22979"},"modified":"2024-06-20T10:28:06","modified_gmt":"2024-06-20T10:28:06","slug":"download-and-restrict-video-files-in-android-app","status":"publish","type":"post","link":"https:\/\/www.bacancytechnology.com\/blog\/download-and-restrict-video-files-in-android-app","title":{"rendered":"Download and Restrict Video Files in Android App"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>A couple of months back, I came across a client requirement who wanted to build a feature to <b>download and restrict video files in Android App<\/b>, just like YouTube, Netflix, Amazon Prime does with us. It took me quite a few days to figure out how to accomplish this requirement, but I ended up with a satisfying solution. If you are looking for this requirement or something similar, hook until the end. <\/p>\n<h2>Client Requirement<\/h2>\n<p>The client made it very clear how the feature should look like. Though, it took time for the team to comprehend and summarize the requirements. <\/p>\n<p>Here was the requirement-<\/p>\n<p class=\"boxed bg--secondary\" style=\"border: 1px solid #c7c7c7; box-shadow: 0 0 40px rgba(0, 0, 0, 0.2);\"><strong>The client wanted to download the video from the URL, save it to the application environment, and play offline (without using the internet) from the environment only. Moreover, he wanted to restrict the user from accessing the video files outside the app environment.<\/strong><\/p>\n<h2>Download and Restrict Video Files in Android App: Our Approach<\/h2>\n<p>After much research, we concluded the three final steps for building the feature: How to <em>Download and Restrict Video Files in Android App<\/em>.<\/p>\n<p>1. Download the video from the URL <\/p>\n<p>2. Encrypt the video file<\/p>\n<p>3. Decrypt the video file at the time of playing<\/p>\n<p>We will dive into each step one by one and implement the codebase in our repository.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.bacancytechnology.com\/blog\/wp-content\/uploads\/2022\/01\/Download-and-Restrict-Video-Files-in-android-app-min-2.jpg\" alt=\"Download and Restrict Video Files in android app\" width=\"1100\" height=\"575\" class=\"aligncenter size-full wp-image-22987\" srcset=\"https:\/\/www.bacancytechnology.com\/blog\/wp-content\/uploads\/2022\/01\/Download-and-Restrict-Video-Files-in-android-app-min-2.jpg 1100w, https:\/\/www.bacancytechnology.com\/blog\/wp-content\/uploads\/2022\/01\/Download-and-Restrict-Video-Files-in-android-app-min-2-300x157.jpg 300w, https:\/\/www.bacancytechnology.com\/blog\/wp-content\/uploads\/2022\/01\/Download-and-Restrict-Video-Files-in-android-app-min-2-1024x535.jpg 1024w, https:\/\/www.bacancytechnology.com\/blog\/wp-content\/uploads\/2022\/01\/Download-and-Restrict-Video-Files-in-android-app-min-2-768x401.jpg 768w\" sizes=\"auto, (max-width: 1100px) 100vw, 1100px\" \/><\/p>\n<h2>Download the Video from the URL<\/h2>\n<p>For downloading the videos, we will use the <a href=\"https:\/\/github.com\/tonyofrancis\/Fetch\" target=\"_blank\" rel=\"noopener\">Fetch<\/a> library. <\/p>\n<p>Update your build.gradle file with the following dependency.<\/p>\n<p><pre>implementation \"androidx.tonyodev.fetch2:xfetch2:3.1.6\"<\/pre>\n<p>This library will let you download the video\/pdf\/image and many more files of different formats. Here are the code snippets for downloading the video using the Fetch library.<\/p>\n<p>First of all, you have to define the fetch configuration like below<\/p>\n<pre>val fetchConfiguration: FetchConfiguration = FetchConfiguration.Builder(this)\r\n  .setDownloadConcurrentLimit(1).enableLogging(true)\r\n  .enableRetryOnNetworkGain(true)\r\n  .build()<\/pre>\n<p>Use <mark>Fetch.getInstance<\/mark> to get the fetch instance<\/p>\n<pre>fetch = Fetch.getInstance(fetchConfiguration)<\/pre>\n<p>Prepare the request as shown below<\/p>\n<pre>val request = videoUrl?.let { \r\n       filePath?.let { \r\n          it1 -> Request(it, it1)\r\n      } \r\n  } <\/pre>\n<p>After that, you need to set the priority of the request like mentioned<\/p>\n<pre>request?.priority = Priority.HIGH (It can be high, low, and normal)<\/pre>\n<p>Set the network type of the request<\/p>\n<pre>request?.networkType = NetworkType.ALL (Global off, unmetered, and wifi only)<\/pre>\n<p>Add header with the <em>clientKey<\/em> as shown<\/p>\n<pre>request?.addHeader(\"clientKey\", \"*************************\") (You can find the clientKey in Fetch dashboard)<\/pre>\n<p>After that you need to put it to the queue by using this code<\/p>\n<pre>request?.let {\r\n   fetch!!.enqueue(it,\r\n     Func { updatedRequest: Request? -> },\r\n     Func { error: Error? -> })\r\n }<\/pre>\n<p>Use the Fetch listeners for more operations<\/p>\n<pre>val fetchListener: FetchListener = object : FetchListener {\r\n            override fun onQueued(\r\n                @NotNull download: Download,\r\n                waitingOnNetwork: Boolean\r\n            ) {\r\n                if (request?.id == download.id) {\r\n                }\r\n            }\r\n\r\n            override fun onProgress(\r\n                @NotNull download: Download,\r\n                etaInMilliSeconds: Long,\r\n                downloadedBytesPerSecond: Long\r\n            ) {}\r\n\r\n            override fun onCompleted(@NotNull download: Download) {\r\n                Log.d(\"downloadingStatus->>\", \"onCompleted: \")\r\n            }\r\n\r\n\r\n            override fun onPaused(@NotNull download: Download) {\r\n                Log.d(\"downloadingStatus->>\",\"video paused\")\r\n            }\r\n\r\n            override fun onResumed(@NotNull download: Download) {\r\n                Log.d(\"downloadingStatus->>\",\"video resumed\")\r\n            }\r\n\r\n            override fun onStarted(\r\n                download: Download,\r\n                downloadBlocks: List<DownloadBlock>,\r\n                totalBlocks: Int\r\n            ) {\r\n                Log.d(\"downloadingStatus->>\",\"video started downloading\")\r\n            }\r\n\r\n            override fun onWaitingNetwork(download: Download) {}\r\n\r\n            override fun onAdded(download: Download) {}\r\n            override fun onCancelled(@NotNull download: Download) {\r\n                Log.d(\"plae->>\",\"video cancelled\")\r\n            }\r\n\r\n            override fun onRemoved(@NotNull download: Download) {\r\n                Log.d(\"plae->>\",\"video removed\")\r\n            }\r\n\r\n            override fun onDeleted(@NotNull download: Download) {\r\n                Log.d(\"plae->>\",\"video deLeted\")\r\n\r\n            }\r\n            override fun onDownloadBlockUpdated(\r\n                download: Download,\r\n                downloadBlock: DownloadBlock,\r\n                totalBlocks: Int\r\n            ) {\r\n                Log.d(\"plae->>\",\"video download block updated\")\r\n\r\n            }\r\n\r\n            override fun onError(\r\n                download: Download,\r\n                error: Error,\r\n                throwable: Throwable?\r\n            ) {\r\n                Log.d(\"plae->>\",\"video onError\")\r\n            }\r\n        }\r\n\r\n   fetch!!.addListener(fetchListener)<\/pre>\n<p>Moving on towards the next step- Encrypting the video file that we have just downloaded.<\/p>\n<p class=\"boxed bg--secondary\" style=\"border: 1px solid #c7c7c7; box-shadow: 0 0 40px rgba(0, 0, 0, 0.2);\"><strong><em><span style=\"font-size:22px; color:#000;\">Looking for skilled Android developers to build scalable and high-performance mobile applications?<\/span><br \/>\nGet in touch with Bacancy, the best Android App Development Company, to <a href=\"https:\/\/www.bacancytechnology.com\/hire-android-app-developer\" target=\"_blank\" rel=\"noopener\">hire android app developers<\/a> without wasting a second.<\/em><\/strong><\/p>\n<h2>Encrypt the Video File<\/h2>\n<p>After downloading and saving the video into the directory, you must encrypt that file. You can use the AES\/GCM\/NoPadding algorithm. In this blog, we will implement the <strong>AES algorithm<\/strong>.<\/p>\n<p>First of all, you need to get the instance as mentioned<\/p>\n<pre>val encipher = Cipher.getInstance(\"AES\")<\/pre>\n<p>Since we integrate the file encryption feature, we need to define the secret key. For generating the secret key, you can use the below code snippet.<\/p>\n<pre>fun generateKey(): SecretKey? {\r\n   \/\/ Generate a 256-bit key\r\n   val outputKeyLength = 256\r\n   val secureRandom = SecureRandom()\r\n  \/\/ Do *not* seed secureRandom! Automatically seeded from system entropy.\r\n   val keyGenerator = KeyGenerator.getInstance(\"AES\")\r\n   keyGenerator.init(outputKeyLength, secureRandom)\r\n   return keyGenerator.generateKey()\r\n }<\/pre>\n<p>Attach the <em>secretKey<\/em> with the encipher <\/p>\n<pre>encipher.init(Cipher.ENCRYPT_MODE, generateKey())<\/pre>\n<p>At last, you need to use <em>CipherInputStream <\/em><\/p>\n<pre>val cis = CipherInputStream(fileInputStream, encipher)\r\n  val buffer = ByteArray(1024) \/\/ buffer can read file line by line to increase speed\r\n        while (cis.read(buffer).also({ read = it }) >= 0) {\r\n             read?.let { fos.write(buffer, 0, it) }\r\n             fos.flush()\r\n        }\r\n    fos.close()<\/pre>\n<h2>Decrypt the Video File<\/h2>\n<p>You won\u2019t play the encrypted videos directly in your app. For that, you have to decrypt the video file. Use the below code snippet to decrypt the encrypted video files.<\/p>\n<pre>val fos = FileOutputStream(decOutFile)\r\nval encipher = Cipher.getInstance(\"AES\")\r\n\r\nval encodedKey: ByteArray = android.util.Base64.decode(\r\n    getFromPrefs(SECRET_KEY, \"\", \"\"),\r\n    android.util.Base64.DEFAULT\r\n)\r\nval originalKey: SecretKey = SecretKeySpec(encodedKey, 0, encodedKey.size, \"AES\")\r\n\r\nencipher.init(Cipher.DECRYPT_MODE, originalKey)\r\n\r\nval cis = CipherInputStream(fileInputStream, encipher)\r\n\r\nval buffer = ByteArray(1024) \/\/ buffer can read file line by line to increase speed\r\n\r\nwhile (cis.read(buffer).also({ read = it }) >= 0) {\r\n   read?.let { fos.write(buffer, 0, it) }\r\n      fos.flush()\r\n}\r\n\r\nfos.close()\r\n<\/pre>\n<p>So, this was about how we can build a feature: How to Download and Restrict Video Files in Android App. Here are a few important notes to keep in mind.<\/p>\n<style>\n.post-content table td, .post-content table th, .wpb_text_column table td, .wpb_text_column table th { vertical-align: top; }\ntable tr td:first-child {\n    min-width: 170px;\n}\n<\/style>\n<div class=\"post-content\">\n<table style=\"width:100%\">\n<tr>\n<th><strong><span style=\"font-size:22px; color:#000;\">Important notes<\/span><\/strong><\/p>\n<p>1. You need to use the same secret key for encryption and decryption; if the secret key is different, it can cause the app to crash.<\/p>\n<p>2. For privately saving the video files, you should not use the external or public file directories; if you use it, it can cause a data leak.\n<\/th>\n<\/tr>\n<\/table>\n<\/div>\n<p> <\/br><\/p>\n<h2>Conclusion<\/h2>\n<p>I hope the blog has helped you achieve your requirement: How to Download and Restrict Video Files in Android App. The <a href=\"https:\/\/www.bacancytechnology.com\/tutorials\/mobile\" target=\"_blank\" rel=\"noopener\">Mobile Application Development tutorials<\/a> page is for you if you are an Android enthusiast! Our mobile app dev team has worked hard to curate blogs and help you quench your thirst for knowledge. So, visit the page and start exploring!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction A couple of months back, I came across a client requirement who wanted to build a feature to download and restrict video files in Android App, just like YouTube, Netflix, Amazon Prime does with us. It took me quite a few days to figure out how to accomplish this requirement, but I ended up [&hellip;]<\/p>\n","protected":false},"author":22,"featured_media":22986,"comment_status":"open","ping_status":"open","sticky":false,"template":"blog-new-template.php","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"_lmt_disableupdate":"no","_lmt_disable":"","footnotes":""},"categories":[1364],"tags":[],"coauthors":[1608],"class_list":["post-22979","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-application-development"],"acf":[],"modified_by":"Binal Prajapati","_links":{"self":[{"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/posts\/22979","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/users\/22"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/comments?post=22979"}],"version-history":[{"count":0,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/posts\/22979\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/media\/22986"}],"wp:attachment":[{"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/media?parent=22979"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/categories?post=22979"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/tags?post=22979"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/coauthors?post=22979"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}