AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:name=".App"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Ball"
tools:targetApi="31">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.demo.ball.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
App:
package com.demo.ball
import android.app.Application
import android.util.Log
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.zip.ZipInputStream
class App : Application() {
companion object {
private const val TAG = "App"
}
override fun onCreate() {
super.onCreate()
GlobalScope.launch {
unTBTZip()
}
}
private fun unTBTZip() {
Log.i(TAG, "unTBTZip startTime: ${System.currentTimeMillis()}")
val tbtDir = File(filesDir, "tbt")
if (tbtDir.exists()) {
Log.i(TAG, "unTBTZip: tbt dir exists")
return
}
if (!tbtDir.mkdirs()) {
Log.i(TAG, "unTBTZip: tbt dir create fail")
return
}
Log.i(TAG, "unTBTZip: tbt dir ${tbtDir.exists()}")
val tbtZipIn = ZipInputStream(assets.open("tbt.zip"))
var nextEntry = tbtZipIn.nextEntry
while (nextEntry != null) {
if (!nextEntry.isDirectory) {
val file = File(tbtDir, nextEntry.name)
Log.i(TAG, "unTBTZip: ${file.exists()}")
val fos = FileOutputStream(file)
val buffer = ByteArray(1024)
var len: Int
while (tbtZipIn.read(buffer).also { len = it } > 0) {
fos.write(buffer, 0, len)
}
fos.close()
}
tbtZipIn.closeEntry()
nextEntry = tbtZipIn.nextEntry
}
tbtZipIn.close()
Log.i(TAG, "unTBTZip endTime: ${System.currentTimeMillis()}")
}
}
MainActivity:
package com.demo.ball
import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.ContactsContract
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import com.demo.ball.databinding.ActivityMainBinding
import java.io.File
class MainActivity : AppCompatActivity() {
private val TAG = MainActivity::class.simpleName
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// Example of a call to a native method
// binding.sampleText.text = stringFromJNI()
// 初始化数据
initData()
// 初始化事件
initEvent()
}
override fun onDestroy() {
super.onDestroy()
}
private fun initData() {
}
private fun initEvent() {
binding.mainStraightBtn.setOnClickListener { straight() }
binding.mainLeftBtn.setOnClickListener { left() }
binding.mainRightBtn.setOnClickListener { right() }
}
private fun straight() {
// path: /data/user/0/com.demo.ball/files
// absolutePath: /data/user/0/com.demo.ball/files
// canonicalPath: /data/data/com.demo.ball/files
// invariantSeparatorsPath: /data/user/0/com.demo.ball/files
// toPath: /data/user/0/com.demo.ball/files
Log.i(TAG, "straight")
Log.i(TAG, "path: ${filesDir.path}")
Log.i(TAG, "absolutePath: ${filesDir.absolutePath}")
Log.i(TAG, "canonicalPath: ${filesDir.canonicalPath}")
Log.i(TAG, "invariantSeparatorsPath: ${filesDir.invariantSeparatorsPath}")
Log.i(TAG, "toPath: ${filesDir.toPath()}")
sendTBT(1)
}
private fun left() {
Log.i(TAG, "left")
sendTBT(2)
}
private fun right() {
Log.i(TAG, "right")
sendTBT(3)
}
private fun sendTBT(id: Int) {
val uri = getTBT(id)
Log.i(TAG, "getTBT: $uri")
if (uri == null) {
Log.i(TAG, "deleteData: tbt not exists")
return
}
runOnUiThread {
binding.mainTbtIv.setImageURI(uri)
}
val shareIntent = Intent(Intent.ACTION_VIEW)
shareIntent.setDataAndType(uri, "image/*")
shareIntent.component = ComponentName("com.demo.baobab", "com.demo.baobab.MainActivity")
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(shareIntent)
}
private fun getTBT(id: Int): Uri? {
val file = File(File(filesDir, "tbt"), "tbt_$id.png")
Log.i(TAG, "getTBT file1: ${file.canonicalPath}")
val tbtFile = File("$filesDir${File.separator}tbt${File.separator}tbt_$id.png")
Log.i(TAG, "getTBT file2: ${tbtFile.canonicalPath}")
if (!tbtFile.exists()) {
Log.i(TAG, "getTBT: file not exists")
return null
}
return FileProvider.getUriForFile(this, "com.demo.ball.fileprovider", tbtFile)
}
}
接收端App:
package com.demo.baobab
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.demo.baobab.data.NotesDbHelper
class MainActivity : AppCompatActivity() {
companion object {
private const val TAG = "MainActivity"
}
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
}
setTBT()
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setTBT()
}
private fun setTBT() {
val tbtUri = intent.data
Log.i(TAG, "initData: $tbtUri")
if (tbtUri == null) {
Log.i(TAG, "setTBT: tbt not exists")
return
}
uiState.tbtIv!!.setImageURI(tbtUri)
}
}