DeepSeek’s large language models have become popular because of their efficiency and relatively lower cost compared to many competing LLMs. They have also released open models under the MIT license, making them accessible to developers for building and experimenting with AI applications.
In this tutorial, let’s learn how to integrate the **DeepSeek API into a Flutter app** and build a simple AI-powered application.
An API Key – you need to add at least $2 to your account
This is what we’ll build.
By default, using an API key directly in the Flutter code is not a good practice. So, for this tutorial, we’ll pass the API key through a text field. For a real application, you can use flutter_secure_storage to store it securely.
We use dependencies,
http — For API integration.
flutter_markdown_plus — LLMs typically return responses in Markdown format. This package helps us render the Markdown response in a more readable and visually appealing way.
One of the issues we face in WebView is the ERR_UNKNOWN_URL_SCHEME error when different URL schemes are not supported by your WebView. Whether it’s happening on your own webpage or someone else’s, it’s still a bad user experience.
I’ve already discussed this in my Android WebView guide. So today, I’m going to discuss this in detail and show you the latest solution.
Because from Android 11, our app cannot completely see or query all the other apps installed on the device. This is actually done for user privacy, and Google also provides a way to handle this by using the tag.
So, we will learn about resolveActivity, the tag, and how to call other apps using their package name and Intent signature.
So, I’ve already created an Android project, and I’ve also created a demo.html file with most of the schemes that can be useful, and I’ve placed it inside the `assets` directory.
I’m using findViewById, not View Binding or Data Binding, so the process can be simpler and easier for you.
By default, Android WebView supports http and https schemes. The problem occurs when the scheme is not related to a webpage, like tel, whatsapp, instagram, UPI, and more.
Here, I created style resources for formatting the scheme text and URL text.
The android-app scheme is used to open a specific app by using its package name.
UPI schemes are one of the commonly used schemes for making UPI payments.
vnd.youtube+YOUTUBE_ID is the way to create a YouTube video scheme URL.
package com.ar.errorunknownschemewebviewandroid
import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.webkit.URLUtil
import androidx.appcompat.app.AppCompatActivity
import android.webkit.WebView
import android.webkit.WebViewClient
import android.webkit.WebResourceRequest
import android.webkit.WebSettings
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
class MainActivity : AppCompatActivity() {
lateinit var webView: WebView
override fun onBackPressed() {
if (webView.canGoBack()) {
webView.goBack()
} else {
super.onBackPressed()
}
}
@SuppressLint("MissingInflatedId")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
webView = findViewById(R.id.webView)
webView.loadUrl("file:///android_asset/demo.html")
webView.webViewClient = MyWebViewClient()
webView.settings.apply {
javaScriptEnabled = true
domStorageEnabled = true
loadsImagesAutomatically = true
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
}
}
inner class MyWebViewClient : WebViewClient() {
@Deprecated("Deprecated in Java")
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
return handleUrl(url)
}
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
return handleUrl(request?.url.toString())
}
private fun handleUrl(url: String?): Boolean {
if (url.isNullOrEmpty()) return false
// Let WebView handle normal web links
if (URLUtil.isNetworkUrl(url)) {
return false
}
if(url.startsWith("myapp")){
val intent = Intent(this@MainActivity, SecondActivity::class.java)
startActivity(intent)
return true
}
try {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
if(intent.resolveActivity(packageManager)!= null){
startActivity(intent)
}
else
{
Toast.makeText(baseContext, "No app found to open this link", Toast.LENGTH_SHORT).show()
}
}
catch (e: Exception){
Toast.makeText(baseContext, "Exception: inside exception", Toast.LENGTH_SHORT).show()
}
return true
}
}
}
Here, I used MyWebViewClient, a subclass of WebViewClient, and overrode the shouldOverrideUrlLoading method. The old method was deprecated in API 24, and the latest version with WebResourceRequest is called before loading the URL in the WebView.
So, this is where our app gets control over the URL or scheme.
We will use a separate method called handleUrl, and we will handle our fixes here.
Returning false means let the WebView take care of the URL, and true means let our app take care of it.
resolveActivity() is used to check whether an app is available without getting an ActivityNotFoundException. If it is not null, we can call the startActivity() method to launch it.
AndroidManifest.xml
We need to provide the <queries> element to add the package name or Intent signature so Android can find the apps that our app needs to interact with.
In the Intent signature, we need to provide the action and scheme data.
We put a separate Intent filter to handle the myapp scheme.
Using an enum makes code easier to maintain, If more llms are added in future.
Before API Integration
You must obtain an API key from the AI provider (OpenAI, Google Gemini, Anthropic, xAI, etc.).
Most AI APIs use the POST method for sending requests.
Set the required headers and request body exactly as shown in the provider’s cURL example or official documentation.
Models, request formats, and response structures may change over time, and some models may be deprecated. Always check the HTTP status code before processing the response.
In a cURL command, -H specifies HTTP headers, while -d sends the request body (payload).
Use Postman (desktop app or web version) to test the API.
After that, open the project in your IDE and open `lib/main.dart`. Remove everything and create a MaterialApp template using `mateapp` (it only works if you are using the Awesome Flutter Snippets extension).
Here, you can see that I have used the Interactions API and sent a POST request with the `gemini-2.5-flash` model. You can also use the latest free-tier model.
Check the status code carefully, as it may be useful. The status code may change due to model overload or if the model has been deprecated.
It works only if the status code is `200`.
The most important parameters are the API key, model, and input.
You can also try it in Postman. It has a web version, so there’s no need to download or install it.
You need to add a loading variable with an initial value of false.
Replace the button UI with the following code.
When the button is clicked, set the loading variable to true. This will rebuild the UI using setState and display a CircularProgressIndicator. Once the API integration is complete, set it back to false and rebuild the UI again using setState.
ENIAC, the first computer, could perform 5,000 additions per second. In comparison, an average person can perform approximately 0.4 additions per second.
This means the first computer was about 12,500 times faster than a human.
Now, in today’s world, computers can perform billions of operations per second. When machines, particularly computers, learn to imitate human behavior—through machine learning—the potential is extraordinary.
One of the noted advantage is that, it does not need a human intervention for making decisions. It will think like human or based how the model is set it up, and make decisions.
It will do as same like human do and sometimes better, especially in repetitive, data-driven, or time-sensitive scenarios.
Personalization
Every client or user is treated as a top priority, No differentiation occurs—each user receives the same level of attention and care. Based on individual patterns, preferences, likes, and dislikes, machine learning models understand what to suggest and what to avoid.
For example, platforms like YouTube, Netflix, and Amazon use machine learning to power their recommendation systems. These systems treat each user uniquely, tailoring content or product suggestions to match personal behavior and interests.
24*7 availability
They are available whenever anyone needs them. No need for rest, sleep, or food like humans do. It means, whenever people need any help from deployed machine learning, it will be done.
Improvement Over Time
Just like experienced professionals improve with time, machine learning models also get better as they are exposed to more data. As the model continues to receive new data after deployment—even data it wasn’t originally trained or tested on—it can adapt, refine its predictions, and improve overall performance.
Using techniques like continuous learning or model retraining, the system becomes more accurate and efficient in handling real-world scenarios.
Handles Large Sets of Data
In this information age, there is a vast amount of data in various formats—text, audio, video, and more. It is very difficult for humans to handle all this data accurately because the chances of mistakes are high. However, machines operate using only 0s and 1s (binary), so they convert every type of data into this format to process and understand it efficiently. While humans converting data into binary might become complex as data volume grows, machines are built to handle and process large datasets quickly and accurately.
Less cost when compared to human
In the long term, its cost is considered to be less compared to humans, and machines can work 24*7. Once implemented, the ongoing costs—such as maintenance, updates, and electricity—are relatively low when spread over many years.
This makes machine learning a cost-effective solution for businesses looking to automate processes and improve efficiency.
New ML Job Opportunities
In the job zone, ML has come with new opportunities such as:
Data Scientist
ML Engineer
MLOps Engineer
Prompt Engineer
with competitive salary.
Beyond technical roles, ML is also creating opportunities in ethical AI, AI policy, and AI product management, reflecting the broader ecosystem around machine learning technologies.
Disadvantages of Machine Learning
Just like its advantages, Machine Learning also has disadvantages.
Let’s talk about that too.
Large Data Needed for Training
The model needs to be trained on a large number of high-quality datasets. If the dataset is small or of low quality, it may lead to poor or average predictions. The model also needs to be trained with new data regularly; otherwise, the ML model will degrade over time.
Resources for Training Are Expensive
For large ML models, training requires CPUs or GPUs. This is actually very expensive, both for renting and buying. They also need expensive infrastructure, as training produces heat that must be controlled to ensure better performance and to prevent overheating.
Job Loss
Due to automation of tasks and significantly better output in less time, there may be increased job losses in different sectors. Most companies have started using AI, which may result in job loss for new joiners or less experienced people. However, ML also creates new opportunities based on machine learning. Still, data typing and most basic tasks are expected to be handled by AI or machine learning in the future.
Manipulation with Malicious Data
Biased and malicious data can significantly alter decisions and lead to incorrect predictions. Manipulation can happen at any time—it may occur during fine-tuning with user feedback or from biased data collected during scraping or training in the machine learning model lifecycle.
Lack of Transparency in How Decisions Are Made (Black Box Problem)
It is often unclear how decisions are made based on the data. In some cases, it is difficult to understand why a particular outcome occurred. This lack of transparency makes debugging and improving predictions more challenging.
Everything undergoing creation or use will have lifecycle.
In Machine learning, There are 2 terms Machine learning lifecycle and machine learning model lifecycle.
They might seem quite similar at first glance, but actually, the Machine Learning Model Lifecycle is just a subset of the broader Machine Learning lifecycle.
In short,
Machine learning lifecycle: tells about the whole process. – managing entire mobile factory.
Machine Learning Model lifecycle: tells only about the machine learning model- managing one Mobile.
At first, I thought that Model Creation -> Model Training -> Model Deployment, these are the steps, but there’s much more to it.
Steps in the Machine learning model lifecycle:
1. Model designing
2. Model training
3. Model Evaluation
4. Model deployment
5. Model monitoring
6. Model maintenance or retraining.
7. Model retirement
1. Model Designing
This is the first phase in model building. Here, we decide what type of algorithm to use, what kind of input and output the model should handle, and where the model will be deployed for user access.
In this phase, we can say that the model structure is completed.
2. Machine training
After creating the model, we need to train it. We already selected an appropriate algorithm and use it to help the machine, learn from the data by identifying patterns.
The data can come from your own sources such as your proprietary records (medical records, bank transactions) or publicly available repositories like Kaggle. This data is then fed to the model, and the model learns from it.
3. Model Evaluation
We need to test the model using unseen data to evaluate its performance. This testing data should not have been used during the training process. Evaluating with new data helps us understand how well the model generalizes to real-world scenarios.
If we skip this step, there’s a high chance the model may fail in production.
4. Model Deployment
To make the model available to users, we need to deploy it—usually by hosting it somewhere. This could be on a server, cloud, or even on edge devices like IoT hardware or mobile phones.
However, large models often can’t be deployed on low-resource devices due to hardware limitations. We can expose the model through an API, allowing users or other systems to access it over the internet.
5. Model monitoring
Still, we need to monitor the model because the model cannot be 100% right in every prediction. Still, many models in production are making mistakes.
ChatGpt, Gemini also says they can make mistakes, right? That’s why this phase is very important. As new data comes in, the model may make wrong decisions.
6. Model retraining
New data or queries can come in during monitoring, after deployment, or from other sources. When this happens, we need to retrain the model to improve its prediction accuracy.
This phase is important for continuously improving the model’s performance.
7. Model retirement
This is the final phase of a machine learning model’s lifecycle. Just like human beings—when we get older, we retire from our job or business.
Similarly, when a model becomes outdated or the data it was trained on is no longer effective, it may fail to make accurate decisions or predictions in the current situation.
In such cases, we need to retire the model to avoid unnecessary resource utilization.
Nowadays, we are surrounded by various AI and machine learning technologies, many of which we use directly or indirectly.
If you use Google or any other search engine to get here, that’s an example.
YouTube, Netflix, Amazon recommendations, self-learning cars, face lock on devices, autocorrect features, and many more.
However, everything started from a thought
Can machines think? —a question posed by Alan Turing, a British mathematician—sparked the beginning of artificial intelligence.
Later, Arthur Samuel, the father of machine learning, created the first machine learning program that taught itself by playing games.
Yes — that’s where it all began.
okay, what is actually Machine Learning?
What Is Machine Learning?
Just like the name says, machines try to learn from data and make decisions. It’s actually like imitating us.
In our childhood, we learned to recognize cats or dogs by seeing them many times.
When we see them again, we understand whether it’s a cat or a dog. The images we saw are stored in our minds, and we compare new ones with our memory. Similarly, machines also learn from data and try to identify or predict things, just like we do.
In the real world, a good example is unlocking a mobile with face scanning. When your phone captures your face for the first time, it stores the image and extracts features like nose shape or jawline, converting them into numbers.
Later, when you try to unlock it, the phone compares your live face with the stored data. If the match is above a certain threshold, it unlocks the phone — saying, “It’s you.”
So, what is data? Anything that carries enough information to help a machine learn and make decisions can be called data.
For example, this blog post could be part of the training data for a model that explains machine learning. But to train a good model, you’d need many such blog posts — from different sources.
Similarly, articles, tweets, photos, audio clips, videos, medical records, and transactions — all of these are forms of data. If they carry useful information, they can be used in machine learning.
Based on the type of data and the way we train the model, machine learning is generally classified into four categories.
Supervised Machine Learning
Unsupervised Learning
Semi – Supervised
Reinforcement
Supervised Machine Learning
A machine learns from labeled data to make predictions — this is called Supervised Machine Learning.
Labeled data means the data comes with a label or description.
For example, you might provide a dog image labeled “dog” or an audio clip labeled “music.”
This helps the machine understand what the data represents.
An example algorithm used in supervised learning is Linear Regression, which can be used to predict house prices.
Unsupervised Learning
This is the opposite of Supervised Learning. It uses only data — no labels or descriptions.
Here, we don’t tell the machine what to learn.
So, the machine needs to find patterns or groups within the data on its own.
For example, K-Means Clustering is an algorithm used for customer segmentation (grouping users based on behavior for targeted marketing).
Semi-Supervised Machine Learning
In this type, the machine is trained with a small amount of labeled data and a large amount of unlabeled data.
Semi-Supervised Machine Learning = Low volume of labeled data + Large volume of unlabeled data.
Example: Self-training + Logistic Regression
Reinforcement Learning
It’s like training a dog. If you tell it to sit and it does, you give it a cookie. Otherwise, no cookie. Just like that, a machine learns by trial and error to reach a specific goal — by getting rewards or not getting them.
eg: Self driving car uses reinforcement learning to improve their driving skills.
Creating viewmodel instance is needed if you are using MVVM architecture. Otherwise, MVVM is incomplete. So in this post, I will tell you about different ways for creating instance of ViewModel in activity or fragment.
By using correct usage of viewmodel, we can avoid ‘Android cannot create instance of viewmodel’ issue also.
okay, let’s start.
First I will tell you in short. So it will save your time.
viewModel() – Used in Jetpack Compose.
by viewModels() – Apply it with Activity or fragment.
by activityViewModels() – Recommended to use when multiple fragments need to share same data and has same instance of Activity
Using ViewModelProvider – old way but still works.
using ViewModelProvider.Factory – Make use of it if you need to pass arguments to viewmodel.
@hiltViewModel – This is from Hilt dependency injection, very helpful if you are using Hilt.
hiltViewModel() – Use it in Composables
Below, I have mentioned versions of different dependencies, so if you need different version, please check the maven repository and use the latest one.
Detailed Version With Code
viewModel()
In Jetpack Compose, viewModel() delegate can be used for creating instance of viewmodel. But before that you need to include the dependencies in gradle file, only then you can use this. If you want to pass parameters, then go with Hilt or ViewModelProvider.Factory
If you are using XML based approach, you can easily create instance of viewmodel using viewModels(). This does not support passing parameters.
3. activityViewModels()
val viewModel: MyViewModel by activityViewModels()
You can use this in your fragment to access instance of viewmodel – better to use when multiple fragment within same activity needs viewmodel instance.
As the name suggests ViewModelProvider gives the viewmodel instance by passing class type of the viewmodel.
5. ViewModelProvider.Factory
val repository = MyRepository()
val factory = MyViewModelFactory(repository)
viewmodel = ViewModelProvider(this, factory)[MyViewModel::class.java]
In most cases, we need to pass a repository or other instances to the viewmodel. So in this example, i am passing a repository to the viewmodel using ViewModelProvider.
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
class MyViewModelFactory(private val repository: MyRepository) :ViewModelProvider.Factory{
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if(modelClass.isAssignableFrom(MyViewModel::class.java)){
return MyViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
Here, the subclass of ViewModelProvider.Factory will receives the instance of repository and creates viewmodel instance for you.
5. Using @HiltViewModel
This approach can be used if you are Hilt dependency injection in your project. But you need to do some changes here, not easy like above steps,
1. You need to add dependency in gradle file.
2. Define subclass of Application and annotate with @HiltAndroidApp.
3. Annotate viewmodel class with @HiltViewModel.
4. if you want to access instance of viewmodel in activity or fragment, annotate those with @AndroidEntryPoint
// id 'com.google.dagger.hilt.android' version '2.48' apply false
// Dagger - Hilt
implementation "com.google.dagger:hilt-android:2.48"
kapt "com.google.dagger:hilt-android-compiler:2.48"
kapt "androidx.hilt:hilt-compiler:1.0.0"
These are the dependencies you need to add in gradle file.
@HiltAndroidApp
class MyApplication: Application()
Create a subclass of Application like above and Use @HiltAndroidApp annotation.
@HiltViewModel
class MainViewModel @Inject constructor(
private val repository: Repository,
application: MyApplication
): AndroidViewModel(application)
If there is any parameters need to pass, create a module and pass from there. So internally hilt will manage. Use @Inject to injecting dependencies through constructor.
@AndroidEntryPoint
class MyFragment : Fragment() {
private val mainViewModel: MainViewModel by viewModels()
hiltViewModel() - call in composable if you are using hilt.
Access like above your viewmodel, do not forget to annotate activity or fragment with @AndroidEntryPoint where you are calling viewmodel.
This is for now, may be I will update later.
Thanks.
From the arrival of Jetpack Compose, developer can store and access color values in 2 ways.
i. Color.kt – Modern approach.
ii. XML – Traditional approach.
both methods are acceptable in jetpack compose.
but which one is better ?
It actually depends on the scenario.
i. For New Jetpack Compose projects
Here, Its better to store colors in Color.kt because its more efficient than resolving xml resources by id. Additionally it provides type safety and IDE can automatically suggest colors.
Using this approach, we can assign different color for light and dark theme. If you are making a multiplatform project. recommended to use this approach.
You can easily found the file in app/src/main/java/com/userName/packagename/ui/theme/Color.kt
val Colors.topAppBarBackgroundColor: Color
@Composable
get() = if(isSystemInDarkTheme()) Color.Black else Color.White
Above code, just implementing dark and light theme based on the isSystemInDarkTheme() method.
ii. Projects with XML + Jetpack compose
In this situation, you can store color values in colors.xml file. So both views and composable can easily access from a central location.
For implementing Dark theme, you can make use of night mode of colors.xml.
Colors.xml file can be found in app/src/main/res/values/colors.xml.
val appBarBackgroundColor = colorResource(R.color.topAppBarBackgroundColor)
Users can still store color values in both files. However for Jetpack Compose, the preferred approach is storing color values in Color.kt file which make IDE to suggest and assures type safety. But if you are working on a project with both Jetpack Compose and XML, you can store values in colors.xml as the traditional way.
Whatever it is, try to store all color code in one file for easy access and maintenance.
When Kotlin arrived, I searched the whole internet to decide: should I learn Kotlin or not?
Back then, some posts convinced me that learning Kotlin would give me a strong advantage as an Android developer.
And they were right.
Now, for anyone searching the internet and wondering whether to learn Jetpack Compose, here’s my answer:
1. Performance
I will start with my favorite part about Jetpack Compose – Live edit.
Why its my favorite?
This one really improved my productivity.
If you did a simple layout change,You dont need to restart the whole application, it just reloads direct in your emulator or real devices. But it still evolving, so sometimes it faces issues with larger projects.
XML lacks this feature due to its imperative UI paradigm and Android view system.
Language Support
Jetpack compose is defined for Kotlin, so if you want to use compose, then you need to write kotlin code. As for now, i don’t seem any plan with java.
XML works well with both languages, so choice of language is not a barrier.
When it comes to rendering layouts, XML perform better for static layouts, but less efficient for complex layouts, because findViewById and binding calls make difficult. But compose is better for complex UIs because it only renders the specific part of the UI that needs to be changed.
Resource Utilization
XML need more effort when rendering complex layout ui. on the other side Jetpack Compose efficiently manage recompositions, but triggering unnecessary recomposition can lead to inefficiencies.
Preview support
Both have built in preview support in Android Studio.
In XML, android studio – we can easily drag and drop our views wherever we want. it make begginer effort less. So that doesn’t end here. Compose also has a nice preview system, renders preview more efficiently than XML.
Jetpack Compose is relatively new, but its community is growing day by day. But for XML, already a huge community out there. as you know, it comes from api level 1. So most of the code are around with XML. Most of the questions you will face will already answered by someone in stackoverflow, reddit or any other site in google. compose not in a long way, they also quickly closing the gap.
Devices Support
Jetpack Compose will not work below api level 21(lolipop), to support running below api 21, then you need to use XML. But however, number of running devices below api 21 is very low. If you are migrating from XML to Compose. sometimes, it might be difficult for larger projects. so you can go for a hybrid approach. such as using compose code in xml.
Using composeView, you can add compose inside XML.
3. Learning curve
i. Beginner
If you are new to android, learning curve for Jetpack Compose feels natural. if you are a beginner in android, but also familiar with Flutter or react native, then it will reduce the intensity of your learning process. However XML may seem easy at first glance, you can quickly understand each tag and its properties, how they work.
XML has abundance of tutorials, books and documentation, making it sufficient for beginner to learn. For compose, developers are creating more tutorials and vlogs, which increases the resources and reduce the gap.
ii. Already an android developer
It become moderate to you, if you are learning compose and also compose not that much documentation or abundance of tutorials out there. So sometimes, you may need to troubleshoot some issues your self.
for XML, there is lot of boilerplate code, also need to switch to java/kotlin code for functionality. For compose, that you can simply do in Kotlin, but must have a better knowledge in Kotlin.
Jetpack Compose vs XML – Summary
Its better to start learning Jetpack compose because that’s the future and it also make app development more productive. But still XML is in the ground, so you can not avoid that. if you are a beginner, most of the projects are in xml, its better to learn xml first, but many companies also hire people with compose due to new projects. so final part, its beneficial to know the basics of xml and go for Jetpack Compose.