不少零基础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 

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐