1.通讯录短信通话记录等权限优先级
google现在的政策是禁止拿用户的通话记录和短信的,不要触碰,通讯录在你有正当使用的场景的时候是可以拿到的但是必须做到一下四点
1.通讯录的应用场景必须合适,使用时弹窗提示用户我们拿通讯录的用途
2.上传之前必须能够提示用户要上传通讯录了,让用户能够做出选择
3.上传不能太频繁
4.隐私政策声明
还有一个问题就是在10.0之后是没法拿到用户的获取通话次数,通话时间了。
2.最新的位置权限要求(goolge于2020 年 4 月 16 日更新)
- 如果应用不再需要利用受位置权限(例如 ACCESS_FINE_LOCATION、ACCESS_COARSE_LOCATION、ACCESS_BACKGROUND_LOCATION)保护的数据来提供应用内的现有功能或服务,就不得再使用这些数据。
- 您不得纯粹出于广告投放或数据分析的目的而请求用户授予位置权限。如果应用在此类数据的许可用途基础上额外将其用于广告投放的目的,则必须遵守我们的广告政策。
- 即使是出于提供现有功能或服务的目的而需要使用位置信息,应用也应请求最小范围的必要权限(即应请求粗略权限、前台权限,而非精细权限、后台权限),并且为相应功能或服务所请求的位置权限级别应在用户的合理预期范围内。例如,如果应用请求或访问后台位置信息,但理由缺乏说服力,我们可能会拒绝该应用。
- 后台位置信息仅可用于提供对用户有益及与应用核心功能相关的功能。
在满足以下条件的情况下,应用可以使用前台服务(当应用仅有前台访问权限时,例如“使用时”)权限访问位置信息:
- 使用此权限使是为了完成用户在应用内发起的操作的后续操作;并且
- 在应用按用户发起操作的意图完成相关用例后立即终止使用该权限。
这次更新对位置的权限使用更严格了,有相关下架风险的要及时修改
3.应用更新的问题
上次有个问题就是我们应用自带更新功能导致从google play下架
根据google邮件提示就是我们自己的APP可能会从我们自己的服务器上下载APK包,把我们自己的内部更新去掉统一走google商店更新就好了。
4.获取用户的wifi_ssid和具体gps定位的问题。
先把我自己获取wifi_ssid的代码贴上来
public static String getWIFISSID() {
String ssid = "";
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O) {
WifiManager mWifiManager = (WifiManager) BaseApplication.getContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
assert mWifiManager != null;
WifiInfo info = mWifiManager.getConnectionInfo();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
return info.getSSID().replace("\"", "");
} else {
return info.getSSID();
}
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1) {
ConnectivityManager connManager = (ConnectivityManager) BaseApplication.getContext().getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
assert connManager != null;
NetworkInfo networkInfo = connManager.getActiveNetworkInfo();
if (networkInfo == null) {
return ssid;
} else if (networkInfo.isConnected()&&networkInfo.getExtraInfo() != nul) {
return networkInfo.getExtraInfo().replace("\"", "");
}
} else {
WifiManager wifiManager = (WifiManager) BaseApplication.getContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
assert wifiManager != null;
WifiInfo info = wifiManager.getConnectionInfo();
int networkId = info.getNetworkId();
List<WifiConfiguration> configurations = wifiManager.getConfiguredNetworks();
for (WifiConfiguration c : configurations) {
if (c.networkId == networkId) {
return c.SSID.replace("\"", "");
}
}
}
return ssid;
}
直接说答案了...如果你的手机版本是9及以上在你获取用户的wifi_ssid和具体gps定位的时候必须要得到ACCESS_FINE_LOCATION这个权限,另外还需要开启手机的gps开关。9以下就没这些问题了。
5.facebook的延迟深度链接问题
需求场景:我们目前的项目都是主要在facebook上投放广告导流,虽然说是facebook后台也提供了一些统计的工具,但是我们自己的广告后台也需要看一些广告的数据,比如区分一些广告流量和自然流量等等。还有为什么我这里只说facebook的延迟深度链接,facebook的常规深度链接在他们的开发者文档和一些博客介绍的很详细了,我贴一个链接有需要的可以看这里的Android Deeplink,Facebook 广告deeplink配置与测试
其实延迟深度链接的配置和一般的深度链接都是一样的可以参考上面的那篇文章,另外测试也是那个网址,不过你需要勾选上延迟选项。测试时有一点需要说明是你的广告后台的测试账号需要和你手机登录facebook的app账号相同。
其实延迟深度链接就是在你的application中增加这一行
AppLinkData.fetchDeferredAppLinkData(this,
new AppLinkData.CompletionHandler() {
@Override
public void onDeferredAppLinkDataFetched(AppLinkData appLinkData) {
if (appLinkData!=null&&appLinkData.getTargetUri()!=null){
//你的上报处理appLinkData.getTargetUri().toString()
}
}
}
);
但是我发现facebook的延迟深度链接TargetUri并不需要严格按照你的配置文件进行推送,因为不管我推的的什么uri过来只要触发了这个回调并且appLinkData不为null,我们就可以拿到他的TargetUri。在看完facebook sdk相关源码后觉得一切顺理成章,在AppLinkData这个类中会异步调用fetchDeferredAppLinkFromServer这个方法,顾名思义就是这个applink这个值是存在facebook后台的。打开APP就会去facebook后台进行查询
public static void fetchDeferredAppLinkData(
Context context,
String applicationId,
final CompletionHandler completionHandler) {
Validate.notNull(context, "context");
Validate.notNull(completionHandler, "completionHandler");
if (applicationId == null) {
applicationId = Utility.getMetadataApplicationId(context);
}
Validate.notNull(applicationId, "applicationId");
final Context applicationContext = context.getApplicationContext();
final String applicationIdCopy = applicationId;
FacebookSdk.getExecutor().execute(new Runnable() {
@Override
public void run() {
fetchDeferredAppLinkFromServer(
applicationContext, applicationIdCopy, completionHandler);
}
});
}
private static void fetchDeferredAppLinkFromServer(
Context context,
String applicationId,
final CompletionHandler completionHandler) {
JSONObject deferredApplinkParams = new JSONObject();
try {
deferredApplinkParams.put("event", DEFERRED_APP_LINK_EVENT);
Utility.setAppEventAttributionParameters(deferredApplinkParams,
AttributionIdentifiers.getAttributionIdentifiers(context),
AppEventsLogger.getAnonymousAppDeviceGUID(context),
FacebookSdk.getLimitEventAndDataUsage(context));
Utility.setAppEventExtendedDeviceInfoParameters(
deferredApplinkParams,
FacebookSdk.getApplicationContext());
deferredApplinkParams.put("application_package_name", context.getPackageName());
} catch (JSONException e) {
throw new FacebookException("An error occurred while preparing deferred app link", e);
}
String deferredApplinkUrlPath = String.format(DEFERRED_APP_LINK_PATH, applicationId);
AppLinkData appLinkData = null;
try {
GraphRequest deferredApplinkRequest = GraphRequest.newPostRequest(
null, deferredApplinkUrlPath, deferredApplinkParams, null);
GraphResponse deferredApplinkResponse = deferredApplinkRequest.executeAndWait();
JSONObject jsonResponse = deferredApplinkResponse.getJSONObject();
if (jsonResponse != null) {
final String appLinkArgsJsonString =
jsonResponse.optString(DEFERRED_APP_LINK_ARGS_FIELD);
final long tapTimeUtc =
jsonResponse.optLong(DEFERRED_APP_LINK_CLICK_TIME_FIELD, -1);
final String appLinkClassName =
jsonResponse.optString(DEFERRED_APP_LINK_CLASS_FIELD);
final String appLinkUrl = jsonResponse.optString(DEFERRED_APP_LINK_URL_FIELD);
if (!TextUtils.isEmpty(appLinkArgsJsonString)) {
appLinkData = createFromJson(appLinkArgsJsonString);
if (tapTimeUtc != -1) {
try {
if (appLinkData.arguments != null) {
appLinkData.arguments.put(ARGUMENTS_TAPTIME_KEY, tapTimeUtc);
}
if (appLinkData.argumentBundle != null) {
appLinkData.argumentBundle.putString(
ARGUMENTS_TAPTIME_KEY, Long.toString(tapTimeUtc));
}
} catch (JSONException e) {
Utility.logd(TAG, "Unable to put tap time in AppLinkData.arguments");
}
}
if (appLinkClassName != null) {
try {
if (appLinkData.arguments != null) {
appLinkData.arguments.put(
ARGUMENTS_NATIVE_CLASS_KEY, appLinkClassName);
}
if (appLinkData.argumentBundle != null) {
appLinkData.argumentBundle.putString(
ARGUMENTS_NATIVE_CLASS_KEY, appLinkClassName);
}
} catch (JSONException e) {
Utility.logd(TAG, "Unable to put tap time in AppLinkData.arguments");
}
}
if (appLinkUrl != null) {
try {
if (appLinkData.arguments != null) {
appLinkData.arguments.put(ARGUMENTS_NATIVE_URL, appLinkUrl);
}
if (appLinkData.argumentBundle != null) {
appLinkData.argumentBundle.putString(
ARGUMENTS_NATIVE_URL, appLinkUrl);
}
} catch (JSONException e) {
Utility.logd(TAG, "Unable to put tap time in AppLinkData.arguments");
}
}
}
}
} catch (Exception e) {
Utility.logd(TAG, "Unable to fetch deferred applink from server");
}
completionHandler.onDeferredAppLinkDataFetched(appLinkData);
}
总结了以下Facebook的延迟深度链接大概原理就是,如果用户尚未安装这个广告的APP点击进入googleplay就会把这个设备的一些信息和TargetUri进行上传,当有用户下载了打开了这个APP就去facebook后台查询获取这个用户特定的TargetUri,由于从facebook跳转到google商店之后的操作facebook是无法控制的所以只能采取这种方法了
网友评论