首页
统计
留言板
关于
更多
友链
Search
1
如果充满遗憾会是怎么样的
86 阅读
2
又一个博客
42 阅读
3
java测试蓝牙延迟
36 阅读
4
vrchat 每日写真[myfz]
32 阅读
5
落叶乌龟? Kirsty刘瑾睿 -若把你
31 阅读
默认分类
代码类
生活
音乐
命令行
笔记
教程
汽车
vrchat
二次元
图片
写真
虚拟偶像
登录
/
注册
Search
标签搜索
教程
代码
笔记
二次元
VRChat
音乐
图片
虚拟偶像
写真
文档
生活
游戏
沐雨酆臻
累计撰写
11
篇文章
累计收到
2
条评论
首页
栏目
默认分类
代码类
生活
音乐
命令行
笔记
教程
汽车
vrchat
二次元
图片
写真
虚拟偶像
页面
统计
留言板
关于
友链
友链
用户登录
登录
搜索到
4
篇与
的结果
2024-08-28
安卓请求/sdcard/Android/data文件夹教程
1、Android 6.0 之前应用只需要在 AndroidManifest.xml 下声明以下权限即可自动获取存储权限:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" //2、Android 6.0 起从Android 6.0开始,除了以上操作以外,还需要在代码中动态申请权限。// 检查是否有存储权限 boolean granted = context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;// 在activity中请求存储权限 requestPermissions(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, 0);3、Android 10Android 10 开始引入了沙盒机制,应用在 sdcard 中默认只能读写私有目录(即/sdcard/Android/data/[应用包名]/),其他目录即便执行前面的操作也无法读写。除非在 AndroidManifest.xml 下声明以下属性:android:requestLegacyExternalStorage="true"这样的话就会暂时停用沙盒机制,正常读写/sdcard下文件。4、Android 11Android 11开始,且应用的目标版本在30及以上,以上的操作也无法再读写sdcard目录。需要声明以下权限:uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" 再动态申请权限:// 检查是否有存储权限 boolean granted = Environment.isExternalStorageManager();// 在activity中请求存储权限 Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) .setData(Uri.parse("package:"+getPackageName())); startActivityForResult(intent, 0);执行以上操作后,sdcard已能够正常读写。但是,有2个特殊的目录仍然无法读写:/sdcard/Android/data 和 /sdcard/Android/obb 。这两个路径需要安卓自带的 DocumentsUI 授权才能访问。首先,最重要的一点,添加 documentfile 依赖(SDK自带的那个版本有问题):implementation "androidx.documentfile:documentfile:1.0.1"Activity请求授权:Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 请求Android/data目录的权限,Android/obb目录则把data替换成obb即可。 Uri treeUri = Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata/document/primary%3AAndroid%2Fdata"); DocumentFile df = DocumentFile.fromTreeUri(this, treeUri); if (df != null) { intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, df.getUri()); } } startActivityForResult(intent, 1);还需要在回调中保存权限:@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); Uri uri; if (data != null && (uri = data.getData()) != null) { // 授权成功 getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } else { // 授权失败 } }然后,使用接口获取文件列表:// Android 11~12转换路径。例如:/sdcard/Android/data,转换成: // Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata/document/primary%3AAndroid%2Fdata") // 路径 /sdcard/Android/data/com.xxx.yyy,转换成: // Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata/document/primary%3AAndroid%2Fdata%2Fcom.xxx.yyy") // 以此类推。 Uri pathUri = pathToUri(path); DocumentFile documentFile = DocumentFile.fromTreeUri(context, pathUri); if (documentFile != null) { DocumentFile[] documentFiles = documentFile.listFiles(); for (DocumentFile df : documentFiles) { // 文件名 String fName = df.getName(); // 路径 String fPath = path + "/" + fName; } }5、Android 13Android 13 开始,上面提到的授权 Android/data、Android/obb目录的方法失效了。说明安卓13无法再直接授权 Android/data 和 Android/obb 这两个目录了。但也并非无计可施。我们可以授权他们的子目录。我们知道,这个目录下的文件夹名称一般都是应用的包名。我们可以直接用应用包名的路径来请求授权。这里要注意,Android 13和Android 11~12的路径转换规则不一样。// Android 13转换路径。例如:/sdcard/Android/data/com.xxx.yyy,转换成: // Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata%2Fcom.xxx.yyy/document/primary%3AAndroid%2Fdata%2Fcom.xxx.yyy") // 路径 /sdcard/Android/data/com.xxx.yyy/files,转换成: // Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata%2Fcom.xxx.yyy/document/primary%3AAndroid%2Fdata%2Fcom.xxx.yyy%2Ffiles") // 以此类推。6、Android 14Android 14对于data、obb目录的授权进一步收紧。在Android 14的后期版本和Android 15预览版中,以上方法已失效(传入uri请求授权只会跳转到sdcard根目录)。这种情况下,想要访问data和obb目录就需要使用Shizuku了。(目前MT、FV就是用这种方法访问的)Shizuku的用法可以查阅相关教程,这里不多赘述。请先将Shizuku启动,便于后续使用。首先,添加Shizuku的依赖:def shizuku_version = "13.1.5" implementation "dev.rikka.shizuku:api:$shizuku_version" // Add this line if you want to support Shizuku implementation "dev.rikka.shizuku:provider:$shizuku_version"AndroidManifest.xml添加以下内容:uses-sdk tools:overrideLibrary="rikka.shizuku.api, rikka.shizuku.provider, rikka.shizuku.shared, rikka.shizuku.aidl" uses-permission android:name="moe.shizuku.manager.permission.API_V23" application provider android:name="rikka.shizuku.ShizukuProvider" android:authorities="${applicationId}.shizuku" android:enabled="true" android:exported="true" android:multiprocess="false" android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" meta-data android:name="moe.shizuku.client.V3_SUPPORT" android:value="true" /application manifest判断Shizuku是否安装:private static boolean isShizukuInstalled() { try { context.getPackageManager().getPackageInfo("moe.shizuku.privileged.api", 0); return true; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return false; }判断Shizuku是否可用:boolean available = Shizuku.pingBinder();检查Shizuku是否授权:boolean granted = Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED;请求Shizuku权限:Shizuku.requestPermission(0);监听授权结果:Shizuku.addRequestPermissionResultListener(listener); Shizuku.removeRequestPermissionResultListener(listener);授权后,自己定义一个aidl文件:IFileExplorerService.aidlpackage com.magicianguo.fileexplorer.userservice; import com.magicianguo.fileexplorer.bean.BeanFile; interface IFileExplorerService { List listFiles(String path); }BeanFile.javapublic class BeanFile implements Parcelable { public BeanFile(String name, String path, boolean isDir, boolean isGrantedPath, String pathPackageName) { this.name = name; this.path = path; this.isDir = isDir; this.isGrantedPath = isGrantedPath; this.pathPackageName = pathPackageName; } /** * 文件名 */ public String name; /** * 文件路径 */ public String path; /** * 是否文件夹 */ public boolean isDir; /** * 是否被Document授权的路径 */ public boolean isGrantedPath; /** * 如果文件夹名称是应用包名,则将包名保存到该字段 */ public String pathPackageName; protected BeanFile(Parcel in) { name = in.readString(); path = in.readString(); isDir = in.readByte() != 0; isGrantedPath = in.readByte() != 0; pathPackageName = in.readString(); } public static final Creator CREATOR = new Creator() { @Override public BeanFile createFromParcel(Parcel in) { return new BeanFile(in); } @Override public BeanFile[] newArray(int size) { return new BeanFile[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString(name); dest.writeString(path); dest.writeByte((byte) (isDir ? 1 : 0)); dest.writeByte((byte) (isGrantedPath ? 1 : 0)); dest.writeString(pathPackageName); } }IFileExplorerService实现类:public class FileExplorerService extends IFileExplorerService.Stub { @Override public List listFiles(String path) throws RemoteException { List list = new ArrayList(); File[] files = new File(path).listFiles(); if (files != null) { for (File f : files) { list.add(new BeanFile(f.getName(), f.getPath(), f.isDirectory(), false, f.getName())); } } return list; } }然后使用Shizuku绑定UserService:private static final Shizuku.UserServiceArgs USER_SERVICE_ARGS = new Shizuku.UserServiceArgs( new ComponentName(packageName, FileExplorerService.class.getName()) ).daemon(false).debuggable(BuildConfig.DEBUG).processNameSuffix("file_explorer_service").version(1); public static IFileExplorerService iFileExplorerService; private static final ServiceConnection SERVICE_CONNECTION = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "onServiceConnected: "); iFileExplorerService = IFileExplorerService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "onServiceDisconnected: "); iFileExplorerService = null; } }; // 绑定服务 public static void bindService() { Shizuku.bindUserService(USER_SERVICE_ARGS, SERVICE_CONNECTION); }绑定之后,调用 aidl 里面的方法来管理文件即可。目前发现了新的Document授权方式,能够在Android 13、14上直接授权Android/data(obb)目录。例1:Android/data目录请求授权,可使用如下Uri: Uri.Builder uriBuilder = new Uri.Builder() .scheme("content") .authority("com.android.externalstorage.documents") .appendPath("tree") .appendPath("primary:A\u200Bndroid/data") .appendPath("document") .appendPath("primary:A\u200Bndroid/data"); // 相当于 content://com.android.externalstorage.documents/tree/primary%3AA%E2%80%8Bndroid%2Fdata/document/primary%3AA%E2%80%8Bndroid%2Fdata例2:Android/data/com.xxx.yyy目录请求授权,可使用如下Uri: Uri.Builder uriBuilder = new Uri.Builder() .scheme("content") .authority("com.android.externalstorage.documents") .appendPath("tree") .appendPath("primary:A\u200Bndroid/data") .appendPath("document") .appendPath("primary:A\u200Bndroid/data/com.xxx.yyy"); // 相当于 content://com.android.externalstorage.documents/tree/primary%3AA%E2%80%8Bndroid%2Fdata/document/primary%3AA%E2%80%8Bndroid%2Fdata%2Fcom.xxx.yyy上面xml的 记得加上
2024年08月28日
12 阅读
0 评论
0 点赞
2024-03-08
java测试蓝牙延迟
在Android中,测试蓝牙延迟(latency)并不直接通过标准的API实现,因为蓝牙延迟受到多种因素的影响,包括蓝牙版本、设备间的距离、信号干扰等。然而,你可以通过编写一些自定义代码来大致测量蓝牙通信的响应时间,从而间接地评估延迟。以下是一个简单的示例,展示了如何使用Android的蓝牙API发送和接收数据,并测量响应时间。请注意,这只是一个基本的示例,并不能提供精确的延迟测量。首先,确保你的Android应用具有蓝牙权限: android.permission.BLUETOOTH android.permission.BLUETOOTH_ADMIN android.permission.BLUETOOTH_PRIVILEGED然后,你可以使用以下代码来发送和接收蓝牙数据: import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.os.Handler; import android.util.Log; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; public class BluetoothLatencyTest { private static final String TAG = "BluetoothLatencyTest"; private static final UUID MY_UUID = UUID.fromString("your-custom-uuid-here"); // 替换为你的UUID private BluetoothAdapter mBluetoothAdapter; private BluetoothDevice mBluetoothDevice; private BluetoothSocket mBluetoothSocket; private OutputStream mOutputStream; private InputStream mInputStream; private Handler mHandler; private long startTime; public BluetoothLatencyTest() { mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mBluetoothDevice = mBluetoothAdapter.getRemoteDevice("device-mac-address-here"); // 替换为目标设备的MAC地址 mHandler = new Handler(); } public void connectAndSendData() { new Thread(() -> { try { mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID); mBluetoothSocket.connect(); mOutputStream = mBluetoothSocket.getOutputStream(); mInputStream = mBluetoothSocket.getInputStream(); // 发送数据并测量响应时间 startTime = System.currentTimeMillis(); mOutputStream.write("Test data".getBytes()); // 等待接收响应 byte[] buffer = new byte[1024]; int bytesRead = mInputStream.read(buffer); if (bytesRead > 0) { long endTime = System.currentTimeMillis(); long latency = endTime - startTime; Log.d(TAG, "Latency: " + latency + " ms"); } mOutputStream.close(); mInputStream.close(); mBluetoothSocket.close(); } catch (IOException e) { e.printStackTrace(); } }).start(); } }在这个示例中,我们创建了一个BluetoothLatencyTest类,它负责连接到远程蓝牙设备、发送数据并测量响应时间。请注意,你需要替换MY_UUID和mBluetoothDevice的值为你的自定义UUID和目标设备的MAC地址。在connectAndSendData方法中,我们创建了一个线程来执行蓝牙连接和数据发送操作。我们使用System.currentTimeMillis()来获取发送数据和接收响应的时间戳,并计算它们之间的差值作为延迟。最后,我们关闭流和套接字。
2024年03月08日
36 阅读
0 评论
1 点赞
2024-03-08
使用js的cookie统计访客量
使用js设置网页访客量利用 用户每次打开浏览器,打开网站的次数来记数,除非清空浏览器的cookie,否则记录的数据就会一直存在 var caution=false function setCookie(name,value,expires,path,domain,secure) { var curCookie=name+"="+escape(value) + ((expires)?";expires="+expires.toGMTString() : "") + ((path)?"; path=" + path : "") + ((domain)? "; domain=" + domain : "") + ((secure)?";secure" : "") if(!caution||(name + "=" + escape(value)).length 0) { date.setTime(date.getTime()-skew) } } var now=new Date() fixDate(now) now.setTime(now.getTime()+365 * 24 * 60 * 60 * 1000) var visits = getCookie("counter") if(!visits) { visits=1; } else { visits=parseInt(visits)+1; } setCookie("counter", visits, now) //document.writeln(visits) document.write(" 同一浏览器:" + visits + " ")
2024年03月08日
6 阅读
0 评论
1 点赞
2024-03-08
php访客量统计
下面写一个简单的php访客量统计随便创建一个php文件,例如:tonji.php 然后在文件里写入 访客统计的php代码 //设置时区为上海 date_default_timezone_set("Asia/Shanghai"); //自动获取当前文件夹 可以更改为你喜欢的名字 $file = dirname(__FILE__).'/tongji.db'; //使用a+ 当文件不存在时会自动创建并写入 $fp=fopen($file,'a+'); $content=''; if (flock($fp,LOCK_EX)){ while (($buffer=fgets($fp,1024))!=false){ $content=$content.$buffer; } $data=unserialize($content); //设置记录键值 $total = 'total'; $month = date('Ym'); $today = date('Ymd'); $yesterday = date('Ymd',strtotime("-1 day")); $tongji = array(); // 总访问增加 $tongji[$total] = $data[$total] + 1; // 本月访问量增加 $tongji[$month] = $data[$month] + 1; // 今日访问增加 $tongji[$today] = $data[$today] + 1; //保持昨天访问 $tongji[$yesterday] = $data[$yesterday]; //保存统计数据 ftruncate($fp,0); // 将文件截断到给定的长度 rewind($fp); // 倒回文件指针的位置 fwrite($fp, serialize($tongji)); flock($fp,LOCK_UN); fclose($fp); //输出数据 $total = $tongji[$total]; $month = $tongji[$month]; $today = $tongji[$today]; $yesterday = $tongji[$yesterday]?$tongji[$yesterday]:0; //设为js输出 如果你想直接输出就把 document.write()删掉 echo "document.write(' 总访问量: {$total}本月: {$month}昨日: {$yesterday}今日: {$today}');"; }
2024年03月08日
24 阅读
0 评论
0 点赞