1.APP又一次因为通讯录问题被下架了
已经做到了这四点了
1.通讯录的应用场景必须合适,使用时弹窗提示用户我们拿通讯录的用途
2.上传之前必须能够提示用户要上传通讯录了,让用户能够做出选择
3.上传不能太频繁
4.隐私政策声明
根据审核小组的发来的邮件,这次的理由是我们使用通讯录的理由不够充分,修改了弹窗和隐私申明相关文案再次提审就没问题了。
2.关于Google强制把compileSdkVersion升级到30带来的问题。
由于google在android 10进行了分区的操作,之前有权限直接操作非私有目录下的文件已经不行了,当时使用的是临时替代方案使用android:requestLegacyExternalStorage="true"。但是在compileSdkVersion升级到30的时候这个标签会自动忽略。还好我们自己应用使用到操作的文件并不多,主要是一个第三方的sdk,包含拍照和选图以及压缩功能,由于作者已经很久没有更新了,只能自己下完包一个个去改了。主要的问题:
1.应用创建文件使用外部存储空间
2.应用操作外部文件。
解决办法:
第一个问题主要是在一些缓存文件的地方放在了外部存储目录,后面就统一使用getExternalCacheDir创建目录了
第二个问题主要是会在图片的压缩还是直接用的绝对路径,这个时候需要拿到文件的Uri,然后将文件复制到我们自己的目录下进行操作。附上我自己的代码
public static File from(Context context, Uri uri) throws IOException {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
String fileName = getFileName(context, uri);
String[] splitName = splitFileName(fileName);
File tempFile = File.createTempFile(splitName[0], splitName[1]);
tempFile = rename(tempFile, fileName);
tempFile.deleteOnExit();
FileOutputStream out = null;
try {
out = new FileOutputStream(tempFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if (inputStream != null) {
copy(inputStream, out);
inputStream.close();
}
if (out != null) {
out.close();
}
return tempFile;
}
private static String[] splitFileName(String fileName) {
String name = fileName;
String extension = "";
int i = fileName.lastIndexOf(".");
if (i != -1) {
name = fileName.substring(0, i);
extension = fileName.substring(i);
}
return new String[]{name, extension};
}
private static String getFileName(Context context, Uri uri) {
String result = null;
if (uri.getScheme().equals("content")) {
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
}
if (result == null) {
result = uri.getPath();
int cut = result.lastIndexOf(File.separator);
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}
private static File rename(File file, String newName) {
File newFile = new File(file.getParent(), newName);
if (!newFile.equals(file)) {
if (newFile.exists() && newFile.delete()) {
Log.d("FileUtil", "Delete old " + newName + " file");
}
if (file.renameTo(newFile)) {
Log.d("FileUtil", "Rename file to " + newName);
}
}
return newFile;
}
private static long copy(InputStream input, OutputStream output) throws IOException {
long count = 0;
int n;
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
while (EOF != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
3.APP获取应用Android列表的问题。
在需要加上android 11android:name="android.permission.QUERY_ALL_PACKAGES"android:name="android.permission.QUERY_ALL_PACKAGES"申明否者无法直接获取应用的安装列表了。并且google明确提出明年这个也会被限制。
解决办法:
1.在google管理后台去提交申请
2.拿到你想查询的应用的包名放到你的androidManifest文件里,在Android11没有权限的情况是可以查到的
4.Unencrypted traffic allowed on all domains
Configure your application's network security to allow unencrypted traffic across all domains. Eavesdroppers can take advantage of this to intercept the data your application sends.If such data is sensitive or could be used to identify a user,this could compromisse user privacy. It is best to allow only encrypted traffic by setting the cleartextTrafficPermitted flag to false,or by adding an encryption policy for specific domains.
由于本身是一个老的项目,本身还有访问一些http外链,所以基本都是明文请求,google play上架为了数据的安全性要求统一使用cleartextTrafficPermitted为false.但是这导致了http链接无法访问,但是你可以在networkSecurityConfig配置文件中配置你信任的CA 如
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">example.com</domain>
<trust-anchors>
<certificates src="@raw/my_ca"/>
</trust-anchors>
</domain-config>
</network-security-config>
具体一些其他的配置可以参考Android网络安全配置
5.Encryption is not secure
Your application uses insecure encryption.
google play给了一个链接针对不安全加密问题的解决方法
看了下项目中设计到加密的地方就一个 接口的全局加密,用的是aes的对称加密,对比google play的文档应该指出的是加密的密钥太容易获取了,可以使用 AndroidKeystore 存储密钥。由于用官方的方法要额外引用三个包,我就没采用官方的方法,直接写了一个jni编译成so用来获取加密的key,再次提审也没有这个问题了。