Table of Contents
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 with a satisfying solution. If you are looking for this requirement or something similar, hook until the end.
Client Requirement
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.
Here was the requirement-
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.
Download and Restrict Video Files in Android App: Our Approach
After much research, we concluded the three final steps for building the feature: How to Download and Restrict Video Files in Android App.
1. Download the video from the URL
2. Encrypt the video file
3. Decrypt the video file at the time of playing
We will dive into each step one by one and implement the codebase in our repository.
Download the Video from the URL
For downloading the videos, we will use the Fetch library.
Update your build.gradle file with the following dependency.
implementation "androidx.tonyodev.fetch2:xfetch2:3.1.6"
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.
First of all, you have to define the fetch configuration like below
val fetchConfiguration: FetchConfiguration = FetchConfiguration.Builder(this)
.setDownloadConcurrentLimit(1).enableLogging(true)
.enableRetryOnNetworkGain(true)
.build()
Use Fetch.getInstance to get the fetch instance
fetch = Fetch.getInstance(fetchConfiguration)
Prepare the request as shown below
val request = videoUrl?.let {
filePath?.let {
it1 -> Request(it, it1)
}
}
After that, you need to set the priority of the request like mentioned
request?.priority = Priority.HIGH (It can be high, low, and normal)
Set the network type of the request
request?.networkType = NetworkType.ALL (Global off, unmetered, and wifi only)
Add header with the clientKey as shown
request?.addHeader("clientKey", "*************************") (You can find the clientKey in Fetch dashboard)
After that you need to put it to the queue by using this code
request?.let {
fetch!!.enqueue(it,
Func { updatedRequest: Request? -> },
Func { error: Error? -> })
}
Use the Fetch listeners for more operations
val fetchListener: FetchListener = object : FetchListener {
override fun onQueued(
@NotNull download: Download,
waitingOnNetwork: Boolean
) {
if (request?.id == download.id) {
}
}
override fun onProgress(
@NotNull download: Download,
etaInMilliSeconds: Long,
downloadedBytesPerSecond: Long
) {}
override fun onCompleted(@NotNull download: Download) {
Log.d("downloadingStatus->>", "onCompleted: ")
}
override fun onPaused(@NotNull download: Download) {
Log.d("downloadingStatus->>","video paused")
}
override fun onResumed(@NotNull download: Download) {
Log.d("downloadingStatus->>","video resumed")
}
override fun onStarted(
download: Download,
downloadBlocks: List,
totalBlocks: Int
) {
Log.d("downloadingStatus->>","video started downloading")
}
override fun onWaitingNetwork(download: Download) {}
override fun onAdded(download: Download) {}
override fun onCancelled(@NotNull download: Download) {
Log.d("plae->>","video cancelled")
}
override fun onRemoved(@NotNull download: Download) {
Log.d("plae->>","video removed")
}
override fun onDeleted(@NotNull download: Download) {
Log.d("plae->>","video deLeted")
}
override fun onDownloadBlockUpdated(
download: Download,
downloadBlock: DownloadBlock,
totalBlocks: Int
) {
Log.d("plae->>","video download block updated")
}
override fun onError(
download: Download,
error: Error,
throwable: Throwable?
) {
Log.d("plae->>","video onError")
}
}
fetch!!.addListener(fetchListener)
Moving on towards the next step- Encrypting the video file that we have just downloaded.
Looking for skilled Android developers to build scalable and high-performance mobile applications?
Get in touch with Bacancy, the best Android App Development Company, to hire android app developers without wasting a second.
Encrypt the Video File
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 AES algorithm.
First of all, you need to get the instance as mentioned
val encipher = Cipher.getInstance("AES")
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.
fun generateKey(): SecretKey? {
// Generate a 256-bit key
val outputKeyLength = 256
val secureRandom = SecureRandom()
// Do *not* seed secureRandom! Automatically seeded from system entropy.
val keyGenerator = KeyGenerator.getInstance("AES")
keyGenerator.init(outputKeyLength, secureRandom)
return keyGenerator.generateKey()
}
Attach the secretKey with the encipher
encipher.init(Cipher.ENCRYPT_MODE, generateKey())
At last, you need to use CipherInputStream
val cis = CipherInputStream(fileInputStream, encipher)
val buffer = ByteArray(1024) // buffer can read file line by line to increase speed
while (cis.read(buffer).also({ read = it }) >= 0) {
read?.let { fos.write(buffer, 0, it) }
fos.flush()
}
fos.close()
Decrypt the Video File
You won’t 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.
val fos = FileOutputStream(decOutFile)
val encipher = Cipher.getInstance("AES")
val encodedKey: ByteArray = android.util.Base64.decode(
getFromPrefs(SECRET_KEY, "", ""),
android.util.Base64.DEFAULT
)
val originalKey: SecretKey = SecretKeySpec(encodedKey, 0, encodedKey.size, "AES")
encipher.init(Cipher.DECRYPT_MODE, originalKey)
val cis = CipherInputStream(fileInputStream, encipher)
val buffer = ByteArray(1024) // buffer can read file line by line to increase speed
while (cis.read(buffer).also({ read = it }) >= 0) {
read?.let { fos.write(buffer, 0, it) }
fos.flush()
}
fos.close()
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.
Important notes
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.
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.
|
Conclusion
I hope the blog has helped you achieve your requirement: How to Download and Restrict Video Files in Android App. The Mobile Application Development tutorials 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!