
单机版deepseek开发安卓APP教程
deepseek比较火,心血来潮我就又试了一下,r1太卡了,我使用的用的是v3模型,让我感到震惊的是,我直接把代码复制进去,居然没有报错,虽然也经历过一些毛病,好在我了解一点安卓开发的流程,APP基本还算能用。于是它给你完整的代码和注释,这里已经可以用了,但是它是用java写的我们让它用kotlin写,并且告诉我们一步一步怎么在最新的Android Studio开发这个软件。我开发的这个软件叫zi
不少零基础DeepSeek编程的教程涌现出来。我看到有的老师用DeepSeek开发了签到软件,用的是HTML开发。确实,相对于用Java、C++来开发,HTML不用编译,不用装环境,直接用浏览器就能运行。而使用Android Studio来开发APP要困难得多。文末有单机版DS分享链接。
deepseek比较火,心血来潮我就又试了一下,r1太卡了,我使用的用的是v3模型,让我感到震惊的是,我直接把代码复制进去,居然没有报错,虽然也经历过一些毛病,好在我了解一点安卓开发的流程,APP基本还算能用。然后我还加了一下功能,比如选择保存的后缀名,一件清空保存目录。用文心一言画了个图标。
我开发的这个软件叫zipsaver,起因是我发现百度网盘直接打开200M以下的文件的时候是不限速的,还可以选择其他应用打开,但是保存到本地的缓存文件是加了权限的,正常情况下打不开。
不过百度网盘加载完文件之后可以选择其他应用打开,这个时候其他应用就有了读取这个文件的权限。
我想能不能把那个要下载的文件改成zip,再做一个假应用直接把那个文件保存起来,这样也算是不限速下载文件了。
虽然只能下载保存200M以内的。
于是利用这个原理,我们开发一个可以打开zip,apk的文件的APP(假装能打开),然后拿到这个文件之后,直接保存在本地。
第一步我们先把需求告诉ai
上面是ai列出来的步骤,最好是能理解为什么要这么做,
- 比如我先要声明告诉系统能处理zip格式的文件
- 再通过Intent 获取百度网盘传递的 ZIP 文件,因为应用间是可以通过Intent通信的。
- 将接收到的 ZIP 文件保存到本地存储,保存文件肯定是需要权限的。
接着让它把每一行代码都给我写注释。
于是它给你完整的代码和注释,这里已经可以用了,但是它是用java写的我们让它用kotlin写,并且告诉我们一步一步怎么在最新的Android Studio开发这个软件。
最好是分步骤进行,不要一句话几个指令。
怎么下载安装Android Studio我就不说了,然后创建项目,具体有点出入,毕竟Android Studio版本在更新。
顺带提一下,创建项目会下载一些东西,要下很久,开热点可能快点。
好了现在我们已经有了一个基础的项目了
但是Android Studio默认已经不生成activity_main.xml了
而deepseek代码里面用的是它,可以用选择创建一个,也可以继续提要求。
按它的修改
如果有错误,继续试试上面两个方法。
好的,无论如何,现在已经不报错了。
测试一下
把文件名称修改从zip,然后直接加载,nice!
那我试试源文件就是zip
明明之前还可以,好在修改成apk格式还可以就加载
修改需求
很好,我觉得我又能行了。:Dweeqw
但是。。。。
文件去哪了。。。我们看一下代码,看不懂就问下ai。
果不其然,被保存在这个软件的私有目录下了。没有权限打开,这不就和原来的百度网盘一样了吗:'(weeqw
无妨,我们已经离成功很近了。
到这里软件已经能够使用了
接下来我们再做一些功能的完善
修改图标,具体可以在网上搜索更详细准确
再添加一键清空按钮
这个它正确理解了,但是我后来才发现安卓的资源不能以数字开头,需要再修改代码。
比较简单我就直接手动重命名,然后改了一下代码里的名字,再把图片放进它说的那个目录
这是成品。
我想能跟到这里的应该不需要我再说怎么用这个软件吧
不过我还是说一下
- 文件改名apk
- 点击打开选择zipsaver
这里是详细的代码(kotlin)及其注释
package com.restartaltair.zipsaver
import android.annotation.SuppressLint
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.OpenableColumns
import android.provider.Settings
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 检查并请求 MANAGE_EXTERNAL_STORAGE 权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
// 请求 MANAGE_EXTERNAL_STORAGE 权限
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
startActivity(intent)
}
}
setContent {
APKSaverApp(intent)
}
}
}
@Composable
fun APKSaverApp(intent: Intent) {
val context = LocalContext.current
var message by remember { mutableStateOf("等待接收文件...") }
var fileType by remember { mutableStateOf(getSavedFileType(context)) } // 获取上次保存的文件类型
var inputType by remember { mutableStateOf("") } // 用户输入的文件类型
// 检查 Intent 的 Action 是否是 VIEW(即从其他 App 打开文件)
if (Intent.ACTION_VIEW == intent.action) {
// 获取文件的 Uri
val fileUri = intent.data
if (fileUri != null) {
// 检查是否有写入外部存储的权限
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// 如果没有权限,请求权限
ActivityCompat.requestPermissions(context as ComponentActivity,
arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE), 1)
} else {
// 如果有权限,直接保存文件
saveFileToLocal(context, fileUri, fileType) { success ->
message = if (success) "文件保存成功" else "文件保存失败"
}
}
}
}
// 显示 UI
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// 显示图片的框框
Box(
modifier = Modifier
.size(200.dp)
.clip(RoundedCornerShape(8.dp))
) {
Image(
painter = painterResource(id = R.drawable.image_123), // 加载 res/drawable 目录下的 image_123.jpg.png
contentDescription = "App 自带图片",
modifier = Modifier.fillMaxSize()
)
}
Spacer(modifier = Modifier.height(16.dp))
Text(text = message, style = MaterialTheme.typography.headlineMedium)
Spacer(modifier = Modifier.height(16.dp))
// 输入文件类型
TextField(
value = inputType,
onValueChange = { inputType = it },
label = { Text("输入保存类型(默认 mp4)") }
)
Spacer(modifier = Modifier.height(16.dp))
// 保存文件类型按钮
Button(onClick = {
if (inputType.isNotEmpty()) {
fileType = inputType
saveFileType(context, fileType) // 保存文件类型
message = "保存类型已修改为:$fileType"
}
}) {
Text("确定")
}
Spacer(modifier = Modifier.height(16.dp))
// 一键清空按钮
Button(onClick = {
clearFiles(context) { success ->
message = if (success) "已清空所有文件" else "清空文件失败"
}
}) {
Text("一键清空")
}
Spacer(modifier = Modifier.height(16.dp))
// 复制路径按钮
Button(onClick = {
val folderPath = File(Environment.getExternalStorageDirectory(), "百度网盘保存").absolutePath
copyToClipboard(context, folderPath)
message = "路径已复制到剪贴板"
}) {
Text("复制保存路径")
}
}
}
}
// 将文件保存到本地
@SuppressLint("Range")
private fun saveFileToLocal(context: android.content.Context, fileUri: Uri, fileType: String, onResult: (Boolean) -> Unit) {
try {
// 创建文件夹路径
val folder = File(Environment.getExternalStorageDirectory(), "百度网盘保存")
if (!folder.exists()) {
folder.mkdirs() // 如果文件夹不存在,创建它
}
// 获取原始文件名
val fileName = context.contentResolver.query(fileUri, null, null, null, null)?.use { cursor ->
if (cursor.moveToFirst()) {
cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
} else {
"downloaded_file"
}
} ?: "downloaded_file"
// 获取文件名(不含后缀)
val fileNameWithoutExtension = fileName.substringBeforeLast(".") // 获取文件名(不含后缀)
// 创建输出文件
val outputFile = File(folder, "$fileNameWithoutExtension.$fileType") // 直接修改后缀名
// 通过 ContentResolver 打开文件的输入流
val inputStream: InputStream? = context.contentResolver.openInputStream(fileUri)
// 创建输出流
val outputStream = FileOutputStream(outputFile)
// 定义缓冲区
val buffer = ByteArray(1024)
// 读取输入流并写入输出流
while (true) {
val readLength = inputStream?.read(buffer) // 读取数据
if (readLength == null || readLength <= 0) break // 如果读取失败或结束,退出循环
outputStream.write(buffer, 0, readLength) // 写入数据
}
// 关闭输入流和输出流
inputStream?.close()
outputStream.close()
// 返回保存成功
onResult(true)
} catch (e: IOException) {
e.printStackTrace()
// 返回保存失败
onResult(false)
}
}
// 清空文件夹中的所有文件
private fun clearFiles(context: android.content.Context, onResult: (Boolean) -> Unit) {
try {
val folder = File(Environment.getExternalStorageDirectory(), "百度网盘保存")
if (folder.exists() && folder.isDirectory) {
val files = folder.listFiles()
if (files != null) {
for (file in files) {
if (file.isFile) {
file.delete()
}
}
}
onResult(true)
} else {
onResult(false)
}
} catch (e: Exception) {
e.printStackTrace()
onResult(false)
}
}
// 保存文件类型到 SharedPreferences
private fun saveFileType(context: android.content.Context, fileType: String) {
val sharedPreferences: SharedPreferences = context.getSharedPreferences("AppSettings", MODE_PRIVATE)
with(sharedPreferences.edit()) {
putString("fileType", fileType)
apply()
}
}
// 从 SharedPreferences 获取保存的文件类型
private fun getSavedFileType(context: android.content.Context): String {
val sharedPreferences: SharedPreferences = context.getSharedPreferences("AppSettings", MODE_PRIVATE)
return sharedPreferences.getString("fileType", "mp4") ?: "mp4" // 默认类型为 mp4
}
// 复制路径到剪贴板
private fun copyToClipboard(context: android.content.Context, text: String) {
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("保存路径", text)
clipboard.setPrimaryClip(clip)
}
只是提供一个ai开发安卓应用的思路而已,这个应用不知道会不会和谐,也不知道还有什么小毛病,只能说勉强能用吧。
我用夸克网盘分享了「无需网络快速部署deepseek」
链接:https://pan.quark.cn/s/d1672cde7b08
更多推荐
所有评论(0)