首页
统计
留言板
关于
更多
友链
Search
1
如果充满遗憾会是怎么样的
63 阅读
2
又一个博客
39 阅读
3
java测试蓝牙延迟
31 阅读
4
vrchat 每日写真[myfz]
29 阅读
5
落叶乌龟? Kirsty刘瑾睿 -若把你
26 阅读
默认分类
代码类
生活
音乐
命令行
笔记
教程
汽车
vrchat
二次元
图片
写真
虚拟偶像
登录
/
注册
Search
标签搜索
教程
代码
笔记
二次元
VRChat
音乐
图片
虚拟偶像
写真
文档
生活
游戏
沐雨酆臻
累计撰写
11
篇文章
累计收到
25
条评论
首页
栏目
默认分类
代码类
生活
音乐
命令行
笔记
教程
汽车
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日
8 阅读
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日
31 阅读
5 评论
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日
21 阅读
0 评论
0 点赞