第三方相关问题
分享相关
关于微信无法分享问题
前置条件:使用友盟第三方分享(包含了微信)
排查步骤:
- 看日志
1.1 提示参数错误:检查渠道、参数(Android参数、网站登记参数)
1.2 提示包名错误:检查Android包名、网站登记包名
微信分享一闪即消失,调不起来微信
-
检查是否使用的是签名包,非签名包不能调试微信分享功能(但若在多渠道中指定在直接运行时的是签名包也是ok的)
-
检查是否有自定义分享缩略图(thumbData),若有,检查自定义缩略图大小不能超过32kb
-
检查是否有自定义描述内容(description),若有,检查自定义描述内容长度不能超过1024
-
关于微信分享的其他限制可查看原码
WXMediaMessage.class
,截取一段:final boolean checkArgs() { if(this.getType() != 8 || this.thumbData != null && this.thumbData.length != 0) { if(this.thumbData != null && this.thumbData.length > '耀') { Log.e("MicroMsg.SDK.WXMediaMessage", "checkArgs fail, thumbData is invalid"); return false; } else if(this.title != null && this.title.length() > 512) { Log.e("MicroMsg.SDK.WXMediaMessage", "checkArgs fail, title is invalid"); return false; } else if(this.description != null && this.description.length() > 1024) { Log.e("MicroMsg.SDK.WXMediaMessage", "checkArgs fail, description is invalid"); return false; } else if(this.mediaObject == null) { Log.e("MicroMsg.SDK.WXMediaMessage", "checkArgs fail, mediaObject is null"); return false; } else { return this.mediaObject.checkArgs(); } } else { Log.e("MicroMsg.SDK.WXMediaMessage", "checkArgs fail, thumbData should not be null when send emoji"); return false; } }
支付相关
微信支付相关
微信支付调用不起来的问题(AsyncTask的坑)
AsyncTask如果有 4、5个线程,则会阻塞。
解决:可换成 RxJava
WXPayEntryActivity 不回调问题
- 注意包名:平台注册的包名+.wxapi.WXPayEntryActivity (完整com.xxx.wxapi.WXPayEntryActivity)
- 注意类名 WXPayEntryActivity 不能写错,在清单文件中进行注册
- 在清单文件中检查WXPayEntryActivity是否有
android:exported="true"
属性(此属性作用是标记可被别的Application组件调用)
//多渠道的情况下,包名不一致,底下的yyy.yyy等导入信息是共用的
package xxx.xxx.test.wxapi;
import org.apache.commons.lang.StringUtils;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import com.tencent.mm.opensdk.constants.ConstantsAPI;
import com.tencent.mm.opensdk.modelbase.BaseReq;
import com.tencent.mm.opensdk.modelbase.BaseResp;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import com.u1city.androidframe.common.toast.ToastUtil;
import yyy.yyy.R;
import yyy.yyy.core.Constants;
import yyy.yyy.sdk.pay.IPayCallBack;
import yyy.yyy.sdk.pay.WXPayHelper;
import yyy.yyy.view.DaogouBaseActivity;
/**
* *
* 微信支付结果回调
*
*/
public class WXPayEntryActivity extends DaogouBaseActivity implements IWXAPIEventHandler
{
private IWXAPI m_WXApi;
private Context context;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState, R.layout.activity_wxpay_entry, R.layout.title_default);
}
@Override
public void initView()
{
context = this;
m_WXApi = WXAPIFactory.createWXAPI(this, Constants.APP_ID);
m_WXApi.handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent)
{
super.onNewIntent(intent);
setIntent(intent);
m_WXApi.handleIntent(intent, this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.wxpay_entry, menu);
return true;
}
@Override
public void onReq(BaseReq arg0)
{
}
@Override
public void onResp(BaseResp p_BaseResp)
{
if (p_BaseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX)
{
int m_PayResult = 0;
if (p_BaseResp.errCode == -2)
{
ToastUtil.showToast(context, "您取消了支付");
m_PayResult = -2;
}
if (p_BaseResp.errCode == -1)
{
String m_ErroInfor = StringUtils.isEmpty(p_BaseResp.errStr) ? "未返回具体原因" : p_BaseResp.errStr;
ToastUtil.showToast(context, "支付失败:" + m_ErroInfor);
m_PayResult = -1;
}
IPayCallBack m_IPayCallBack = WXPayHelper.getIPayCallBack();
if (m_IPayCallBack != null)
{
m_IPayCallBack.payCallBack(m_PayResult);
}
finishAnimation();
}
}
}
微信支付回调java.lang.IllegalStateException: Already attached
解决:在WXPayEntryActivity.java
的onCreate
中用了自定义的super.onCreate(savedInstanceState, R.layout.activity_wxpay_entry, R.layout.title_default);
改成系统的super.onCreate(savedInstanceState);
即可
微信支付:弹起支付页面但是原来的页面走了onPause没有走onStop方法
命令adb shell dumpsys activity | findstr Run
查看当前运行的Activity
猜测com.tencent.mm/.plugin.wallet_index.ui.OrderHandlerUI
是个Activity当成加载的loading(dialog),此时底部的PayActivity
还处于可见状态(调起onPause()
),之后OrderHandlerUI
自身又调起com.tencent.mm/.framework.app.UIPageFragmentActivity
这个Activity,使得PayActivity
不可见
但UIPageFragmentActivity
和PayActivity
不是相邻的(中间隔了一个OrderHandlerUI
)所以影响不到PayActivity
的生命周期,即不会触发PayActivity
的onStop
方法
微信WAP支付提示”商家参数格式有误,请联系商家解决"
问题:安卓webView
内的外部商家开发的链接,点立即购买后调起微信这一步出现“商家参数格式有误,请联系商家解决”
解决:找到微信官方给出的文档
另外参考另一篇解决方案
在WebView
的shouldOverrideUrlLoading
内加上
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("https://wx.tenpay.com")) {
//H5微信支付要用,不然说"商家参数格式有误"
Map<String, String> extraHeaders = new HashMap<String, String>();
extraHeaders.put("Referer", "http://yx.dagangcheng.com");//替换成自己的“商户申请H5时提交的授权域名”
view.loadUrl(url, extraHeaders);
return true;
} else if (url.startsWith("weixin://wap/pay?") || url.startsWith("http://weixin/wap/pay") ) {//上面的代码校验通过后会组装成“:weixin://wap/pay?prepayid...”格式的链接来调起微信支付(通过weixin://wap/pay?的协议调起的,其中weixin:与http类似)
try {
startActivity(new Intent("android.intent.action.VIEW", Uri.parse(url)));
} catch (Exception e) {
//做些其他的错误提示,比如以下的
/*new CancelOrOkDialog(H5PayActivity.this, getString(R.string.h5_pay_no_pay_app)) {
@Override
public void ok() {
Intent intent = new Intent(H5PayActivity.this, MainActivity.class);
intent.putExtra(Constants.SELECTTAB, 0);
startActivity(intent);
}
};*/
}
return true;
}
}
}
微信小程序支付,无法返回应用
问题:App调用微信小程序支付,跳到小程序窗口后,部分手机(如vivo)点击“返回应用”无反应
解决:在App内点微信分享后再次小程序支付,可以返回App,所以分析应该是微信没有保存App信息到本地的原因。无法解决。
集成支付宝 sdk 遇到的问题
Duplicate zip entry[classes.jar:com/ut/device/UTDevice.class]
原因:支付 sdk 和友盟 sdk 都有这个文件
解决:支付 sdk 下载个不再 utdevice 的 aar 包
Failed to resolve::alipaySdk-15.6.8-20191021122455-noUtdid:Open File
原因:alipay 项目找不到这个 aar 文件
解决:在项目的根目录 build.gradle
中增加(flatDir
)如下代码:
/**
* allprojects 代码块用来配置工程中所有 modules 都要使用的仓库和依赖
* 但是你应该在每个 module 级的 build 文件中配置 module 独有的依赖。
* 对于一个新工程,Android Studio 默认会让所有 modules 使用 JCenter 仓库和 Google 的 Maven 仓库
*/
allprojects {
repositories {
jcenter()
mavenCentral()
//使用开源中国的maven库代替jcenter()
//阿里云的(速度飞快):http://maven.aliyun.com/nexus/content/groups/public/
// maven {
// url 'http://maven.aliyun.com/nexus/content/groups/public'
// }
maven { url "https://jitpack.io" }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
maven {
url 'https://maven.google.com/'
name 'Google'
}
//支付宝需要增加这个
flatDir {
dirs 'libs'
dirs '../AliSDK/libs'
}
}
//全局设定编码与java版本
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
集成威富通支付遇到的问题
注意:别坚信demo,别坚信文档!!!(豹奔–膳闯项目)
-
android端,本地不做预下单(不安全)。预下单是后台做的。查询订单也是后台的。android端做的:接收后台提供的token_id,并结合微信appid调起支付的sdk就ok了(注意在注册清单文件中对应页面的Activity里要写上这个微信appid)
-
后台的坑:appid要改成sub_appid,demo和文档要结合着来看。
支付宝支付
集成支付宝支付出现{resultStatus=4000, result=, memo=系统繁忙,请稍后再试}
-
{resultStatus=4000, result=, memo=系统繁忙,请稍后再试}
如果APPID,PID,TARGET_ID,RSA2_PRIVATE都正确的情况下,看手机是否已安装支付宝应用
-
{resultStatus=4000, result={“alipay_trade_app_pay_response”:{“code”:“40006”,“msg”:“Insufficient Permissions”,“sub_code”:“isv.insufficient-isv-permissions”,“sub_msg”:“ISV权限不足,建议在开发者中心检查应用是否上线”}}, memo=}
应用没有上线的原因
第三方登录
友盟 微信登录授权不走回调
问题:微信登录没有获取到用户信息、没有反应
解决:
- 确认能否进入微信客户端授权确认页面
如果不能进入微信授权页面,或者在微信客户端账号未登录状态下只能进入输入账号密码页面,说明签名验证失败,请检查签名是否一致。
- 进入微信授权确认页面,点击后没有返回对应的用户资料
进入这一步多半是由于微信回调配置错误导致,首先打开 Debug 模式日志,查看回调Activity(WXEntryActivity.java
) 配置是否正常。
如果确认回调 Activity 及AndroidManifest.xml
中微信相关配置都正确,需要确认 WXEntryActivity.java
中有无复写其他 SDK(如支付、微信原生登录)的回调逻辑,UShare SDK
要求留一个空类,相关回调结果在jar
中实现,如微信精简版中 Demo 里的配置:
public class WXEntryActivity extends WXCallbackActivity{}
推送
关于友盟无法推送问题
-
排查步骤:
- ios和安卓是否都不可以,排查是否是后台问题
- 看参数,是否加IP白名单
2.1. 看gradle中配置的参数、看友盟控制台配置的参数、看后台配置的参数(注意正式线还是测试线)
2.2. 在友盟控制台模拟发送,(从AS取友盟Token)发送给特定用户 - ios证书是否配置了
-
又一城安卓友盟推送问题排查步骤
-
确认安卓和ios是否单端出现问题,如果单端出现问题,那么大概率是APP端的问题,需要各自排查问题;
-
单端出现问题的情况下,需要先排查与友盟的对接是否出现问题,先在友盟的后台通过推送测试消息,
可同时测试独立用户(设备码)和特定用户(别名),如果无法推送成功,那么就是与友盟的对接出现了问题,需要排查参数的配置是否出错; -
排查参数配置时需要排查代码、友盟后台、后台的AppKey、MasterSecret、MessageSecret的参数配置,
IOS还需要排查证书;其中后台的配置地址为:
后台顾客端参数配置:域名/weChat/appGenerationSuccess
后台导购端参数配置:域名/appPackage/guideAppGenerationSuccess
如果参数配置没有问题,通过友盟后台推送还是失败,那可能是代码中出现错误; -
在双端友盟推送能够成功,并且在确定各端友盟对应应用已配置了IP白名单(IP为域名对外访问对应的IP。比如阿里云给的IP)的情况下
(注:需要确定友盟控制台已添加IP白名单)在确定白名单已经配置的情况下,
Android端和IOS端会同时出现问题,那么大概率可能是后台的问题,需要告知后台帮忙排查解决问题 -
推送失败信息如下:
什么是DeviceTokenNotForTopic- DeviceToken和当前的bundleID不匹配
一般是推送证书有问题,需要重新上传证书。
注:在项目未发布的时候就要针对推送进行测试,及时发现问题并解决,如果发现了推送问题,可参照以上的步骤进行排查
- DeviceToken和当前的bundleID不匹配
-
关于友盟后台推送可以收到,又一城后台推送收不到
1. 排查参数:查看友盟后台登记的参数、app中的参数、又一城后台登记的第三方参数(注意:**有可能message和secret参数顺序填反**) 2. 排查友盟后台是否有填IP白名单
-
友盟注册报错 s=-11,s1=accs bindapp error
排查:
- 检查参数、IP白名单、后台填的参数
- 代码中注册逻辑要加
mPushAgent.setResourcePackageName(packageName);
- 有可能是跟阿里百川一起使用,导致的冲突(有可能是so包冲突;有可能是百川失败)
友盟推送 java.lang.IllegalArgumentException: ResClass未初始化,请确保你已经添加了必要的资源。同时确保你在混淆文件中添加了xxx.xxx.xidamen.R$*
问题描述:友盟注册成功,取到正确的别名和token了。用自定义样式推送的消息,报“java.lang.IllegalArgumentException: ResClass未初始化,请确保你已经添加了必要的资源。同时确保你在混淆文件中添加了xxx.xxx.xidamen.R$*”
解决:实际是缺少了.so包,报错中还有报缺少so包的错误。IMLib/libs下缺少了so包
ResClass未初始化,请确保你已经添加了必要的资源
ResClass未初始化,请确保你已经添加了必要的资源…
友盟推送的过程中报这个错误。
排查步骤:
1、友盟控制台查看了参数、app中配置的参数、后台配置的参数,一致。–》app端可以接收消息
2、友盟控制台是否添加了IP白名单
3、是否因为是多渠道而没有在友盟注册中添加packageName,这个packageName需要和AndroidManifest.xml中的包名一致
SBC2.0 最后排查到是第3点的问题
解决:
1、在PushCenter.java中添加参数
2、在调用这个注册的地方添加参数
3、注意这个packageName要与AndroidManifest.xml中的包名一致
后台推送消息,手机接收不到的问题
排查过程:
-
先对比ios和安卓看两端是否有同样问题
- 如果有同样问题,检查参数配置(友盟控制台、手机端、后台)要一致、友盟控制台的IP白名单是否配置
-
因为ios未上架AppStore无法推送,排除与ios对比的可能性,从参数、ip白名单等方面排查
-
检查参数(友盟控制台、后台、安卓端)一致,尝试从友盟控制台推送消息,安卓可接收到【得出参数无误的结论】
-
检查友盟控制台IP白名单,无误【得出不是IP白名单问题】
-
通过后台网页发送推送消息,后台服务抓取参数进行比对,发现友盟注册别名"alias_type"错误
-
别名错误的原因是groovy中设置的
“\\”
导致首字母消失【详解见 https://shenbh.top/gradle知识/Gradle笔记/下的groovy的manifestPlaceholders属性值取值问题 这个笔记】
IM即时通讯
关于百川IM在安卓8不能调起问题(阿里已经不维护了)
现象:PMS顾客端IM聊天在安卓8不能调起,会报登录超时。安卓8以下的正常。导购端的都正常(包括在安卓8)
排查步骤:
- 排查是否是tcmService进程没有开启(在AS的logcat的标题栏上看的)
- 排查gradle中的targetVersion的值,IM不支持太高的版本(解决:降低targetVersion)
原因:辣苹果顾客端targetVersion设置成27,而云旺不支持这么高的版本。
解决:降低targetVersion
百川在安卓8以上无法推送问题
现象:导购端退到后台,顾客端发送消息。在安卓6上导购端状态栏有新消息提示,在安卓8以上没有新消息提示
解决:【暂不解决,百川都不维护了,看看客户是否换成融云】
地图&定位
高德地图相关
key、定位相关
- 如果误删高德地图控制台申请的应用和key
可以进行添加新的key,同时要更改代码注册清单文件中对应的apikey的值 - 同一个应用可以申请多个key,不过注册清单文件中的apikey只能一个,所以限制了只能有一个生效
(当然如果是两个编辑器进行编译的话,那么可以同时用到两个) - 高德地图控制台申请应用名,即使删除了也不能重新用这个名字
- 注意:在安卓6.0以上的sdk中,权限是要写在代码中,在注册清单文件中写的无效。(只能在手机的设置里信任此应用方可),否则会报“缺少定位权限”的异常
- 删除了高德地图控制台申请的key,应用中会报“KEY鉴权失败”的异常
aMap = mapView.getMap();一直报 NullPointException
解决:在app.build
中添加
sourceSets{
main{
jniLibs.srcDirs = ['libs']
}
instrumentTest.setRoot('tests')
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
完整代码
app.build
apply plugin: 'com.android.application'
task clean(type:Exec){
ext.lockhunter = '\"C:\\LockHunter.exe\"'
def buildDir = file(new File("build"))
commandLine 'cmd' , "$lockhunter", '/delete', '/silent',buildDir
}
android {
compileSdkVersion 23
buildToolsVersion '23.0.3'
defaultConfig {
applicationId "com.xxx"
minSdkVersion 17
targetSdkVersion 19
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
productFlavors {
}
sourceSets{
main{
jniLibs.srcDirs = ['libs']
}
instrumentTest.setRoot('tests')
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
}
dependencies {
compile fileTree(includes: ['*.jar'], dir: 'libs')
compile files('libs/fastjson-1.2.4.jar')
compile files('libs/nineoldandroids-2.4.0.jar')
compile files('libs/okhttp-3.4.1.jar')
compile files('libs/okio-1.9.0.jar')
compile files('libs/universal-image-loader-1.9.2.jar')
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.flipboard:bottomsheet-core:1.5.1'
compile files('libs/AMap_Location_V3.5.0_20170731.jar')
compile files('libs/AMap_Search_V5.2.1_20170630.jar')
compile files('libs/Android_Map3D_SDK_V5.2.1_20170630.jar')
compile files('libs/Volley.jar')
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxx"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="19" />
<!-- 地图包、搜索包需要的基础权限 -->
<!-- 允许程序打开网络套接字 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 允许程序设置内置sd卡的写权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 允许程序获取网络状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 允许程序访问WiFi网络信息 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 允许程序读写手机状态和身份 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 允许程序访问CellID或WiFi热点来获取粗略的位置 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--用于读取手机当前的状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!--用于申请调用A-GPS模块-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<application
android:name="com.xxx.MyApplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="b5eae3aeaae6a5439226e657ac997d08" />
<!--主要界面-->
<activity
android:name="com.xxx.personal.locate.MarkerAnimationActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 定位需要的服务 使用2.0的定位需要加上这个 -->
<service android:name="com.amap.api.location.APSService" />
</application>
</manifest>
MarkerAnimationActivity.java
package com.xxx.personal.locate;
import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import com.amap.api.maps.AMap;
import com.amap.api.maps.MapView;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.CameraPosition;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.animation.Animation;
import com.amap.api.maps.model.animation.ScaleAnimation;
import com.amap.api.maps.model.animation.TranslateAnimation;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.geocoder.GeocodeResult;
import com.amap.api.services.geocoder.GeocodeSearch;
import com.amap.api.services.geocoder.RegeocodeAddress;
import com.amap.api.services.geocoder.RegeocodeQuery;
import com.amap.api.services.geocoder.RegeocodeResult;
import com.xxx.MyBaseActivity;
import com.xxx.R;
/**
* AMapV2地图中简单介绍一些Marker的用法.
* Marker动画功能介绍
*/
public class MarkerAnimationActivity extends MyBaseActivity implements View.OnClickListener,AMap.OnCameraChangeListener,GeocodeSearch.OnGeocodeSearchListener {
private MarkerOptions markerOption;
private AMap aMap;
private MapView mapView;
private LatLng latlng = new LatLng(39.761, 116.434);
Marker screenMarker = null;
Marker growMarker = null;
GeocodeSearch geocodeSearch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.marker_animation_activity);
/*
* 设置离线地图存储目录,在下载离线地图或初始化地图设置; 使用过程中可自行设置, 若自行设置了离线地图存储的路径,
* 则需要在离线地图下载和使用地图页面都进行路径设置
*/
// Demo中为了其他界面可以使用下载的离线地图,使用默认位置存储,屏蔽了自定义设置
// MapsInitializer.sdcardDir =OffLineMapUtils.getSdCacheDir(this);
mapView = (MapView) findViewById(R.id.map);
mapView.onCreate(savedInstanceState); // 此方法必须重写
init();
}
/**
* 初始化AMap对象
*/
private void init() {
Button clearMap = (Button) findViewById(R.id.growMarker);
clearMap.setOnClickListener(this);
Button resetMap = (Button) findViewById(R.id.jumpMarker);
resetMap.setOnClickListener(this);
if (aMap == null) {
aMap = mapView.getMap();
}
aMap.setOnMapLoadedListener(new AMap.OnMapLoadedListener() {
@Override
public void onMapLoaded() {
addMarkersToMap();
}
});
// 设置可视范围变化时的回调的接口方法
aMap.setOnCameraChangeListener(new AMap.OnCameraChangeListener() {
@Override
public void onCameraChange(CameraPosition position) {
}
@Override
public void onCameraChangeFinish(CameraPosition postion) {
//屏幕中心的Marker跳动
startJumpAnimation();
}
});
aMap.setOnCameraChangeListener(this);
geocodeSearch = new GeocodeSearch(this);
geocodeSearch.setOnGeocodeSearchListener(this);
}
/**
* 方法必须重写
*/
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
/**
* 方法必须重写
*/
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
/**
* 方法必须重写
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
/**
* 方法必须重写
*/
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
/**
* 在地图上添加marker
*/
private void addMarkersToMap() {
addMarkerInScreenCenter();
addGrowMarker();
}
/**
* 在屏幕中心添加一个Marker
*/
private void addMarkerInScreenCenter() {
LatLng latLng = aMap.getCameraPosition().target;
Point screenPosition = aMap.getProjection().toScreenLocation(latLng);
screenMarker = aMap.addMarker(new MarkerOptions()
.anchor(0.5f,0.5f)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.purple_pin)));
//设置Marker在屏幕上,不跟随地图移动
screenMarker.setPositionByPixels(screenPosition.x,screenPosition.y);
}
/**
* 添加一个从地上生长的Marker
*/
public void addGrowMarker() {
if(growMarker == null) {
MarkerOptions markerOptions = new MarkerOptions().icon(BitmapDescriptorFactory
.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
.position(latlng);
growMarker = aMap.addMarker(markerOptions);
}
startGrowAnimation();
}
/**
* 地上生长的Marker
*/
private void startGrowAnimation() {
if(growMarker != null) {
Animation animation = new ScaleAnimation(0,1,0,1);
animation.setInterpolator(new LinearInterpolator());
//整个移动所需要的时间
animation.setDuration(1000);
//设置动画
growMarker.setAnimation(animation);
//开始动画
growMarker.startAnimation();
}
}
/**
* 屏幕中心marker 跳动
*/
public void startJumpAnimation() {
if (screenMarker != null ) {
//根据屏幕距离计算需要移动的目标点
final LatLng latLng = screenMarker.getPosition();
Point point = aMap.getProjection().toScreenLocation(latLng);
point.y -= dip2px(this,125);
LatLng target = aMap.getProjection()
.fromScreenLocation(point);
//使用TranslateAnimation,填写一个需要移动的目标点
Animation animation = new TranslateAnimation(target);
animation.setInterpolator(new Interpolator() {
@Override
public float getInterpolation(float input) {
// 模拟重加速度的interpolator
if(input <= 0.5) {
return (float) (0.5f - 2 * (0.5 - input) * (0.5 - input));
} else {
return (float) (0.5f - Math.sqrt((input - 0.5f)*(1.5f - input)));
}
}
});
//整个移动所需要的时间
animation.setDuration(600);
//设置动画
screenMarker.setAnimation(animation);
//开始动画
screenMarker.startAnimation();
} else {
Log.e("amap","screenMarker is null");
}
}
//dip和px转换
private static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
/*
* 从地上生长的Marker
*/
case R.id.growMarker:
startGrowAnimation();
break;
/*
* marker 跳动动画
*/
case R.id.jumpMarker:
startJumpAnimation();
break;
default:
break;
}
}
@Override
public void onCameraChange(CameraPosition cameraPosition) {
LatLng target = cameraPosition.target;
// System.out.println(target.latitude+"---"+target.longitude);
getAddressByLatlng(target);
}
@Override
public void onCameraChangeFinish(CameraPosition cameraPosition) {
}
@Override
public void onRegeocodeSearched(RegeocodeResult regeocodeResult, int i) {
if (i == 0) {
if (regeocodeResult != null && regeocodeResult.getRegeocodeAddress() != null) {
RegeocodeAddress regeocodeAddress = regeocodeResult.getRegeocodeAddress();
String formatAddress = regeocodeAddress.getFormatAddress();
String simpleAddress = formatAddress.substring(9);
System.out.println("查询经纬度对应详细地址:\n" + simpleAddress);
} else {
// NToast.shortToast(AMAPLocationActivity.this, "没有搜索到结果");
System.out.println();
}
} else {
// NToast.shortToast(AMAPLocationActivity.this, "搜索失败,请检查网络");
System.out.println();
}
}
@Override
public void onGeocodeSearched(GeocodeResult geocodeResult, int i) {
}
private void getAddressByLatlng(LatLng latLng) {
//逆地理编码查询条件:逆地理编码查询的地理坐标点、查询范围、坐标类型。
LatLonPoint latLonPoint = new LatLonPoint(latLng.latitude, latLng.longitude);
RegeocodeQuery query = new RegeocodeQuery(latLonPoint, 500f, GeocodeSearch.AMAP);
//异步查询
geocodeSearch.getFromLocationAsyn(query);
}
}
百度定位移到项目中不可用
- 检查权限;检查是不是重新申请了key(一个包名对应一个key);
- 用百度定位的时候要用
getApplicationContext()
,因为当前的context被销毁了虽然不报错,但是也不提供定位。
Bugly相关
Bugly 无法上报的问题
- 可能是加了自己的异常捕获导致的
解决:去掉自己的异常捕获
GreenDao的问题
- 复合主键
在数据库表多对多的关系中,中间表使用的是复合主键,在GreenDao中复合主键的表达方式是:
// 复合主键
@Entity(indexes = { @Index(value = "studentId, teacherId", unique = true)})
public class TeacherStudent{
private long studentId;
private long teacherId;
}
- 多对多关系:
@Entity
public class Student{
@Id
private long id;
@ToMany
@JoinEntity(entity = TeacherStudent.class, sourceProperty = "studentId", targetProperty = "teacherId")
private List<Teacher> teachers;
}
@Entity
public class Teacher{
@Id
private long id;
@ToMany
@JoinEntity(entity = TeacherStudent.class, sourceProperty = "teacherId", targetProperty = "studentId")
private List<Student> students;
}
- 查询结果出现重复项:
当查询结果出现重复项的时候,使用函数.distinct()取消所有的重复项。 - 如果GreenDao报错时,首先是将自动生成的代码段删除然后重新编译
ARouter
“W/ARouter::: ARouter::No postcard![ ]”
这个Log正常的情况下也会打印出来,如果您的代码中没有实现DegradeService和PathReplaceService的话,因为ARouter本身的一些功能也依赖 自己提供的Service管理功能,ARouter在跳转的时候会尝试寻找用户实现的PathReplaceService,用于对路径进行重写(可选功能),所以如果您没有 实现这个服务的话,也会抛出这个日志
推荐在app中实现DegradeService、PathReplaceService
“W/ARouter::: ARouter::There is no route match the path [/xxx/xxx], in group [xxx][ ]”
- 通常来说这种情况是没有找到目标页面,目标不存在
- 如果这个页面是存在的,那么您可以按照下面的步骤进行排查
- 检查目标页面的注解是否配置正确,正确的注解形式应该是 (@Route(path="/test/test"), 如没有特殊需求,请勿指定group字段,废弃功能)
- 检查目标页面所在的模块的gradle脚本中是否依赖了 arouter-compiler sdk (需要注意的是,要使用apt依赖,而不是compile关键字依赖)
- 检查编译打包日志,是否出现了形如 ARouter::�Compiler >>> xxxxx 的日志,日志中会打印出发现的路由目标
- 启动App的时候,开启debug、log(openDebug/openLog), 查看映射表是否已经被扫描出来,形如 D/ARouter::: LogisticsCenter has already been loaded, GroupIndex[4],GroupIndex > 0
ARouter开启InstantRun之后无法跳转(高版本Gradle插件下无法跳转)?
因为开启InstantRun之后,很多类文件不会放在原本的dex中,需要单独去加载,ARouter默认不会去加载这些文件,因为安全原因,只有在开启了openDebug之后 ARouter才回去加载InstantRun产生的文件,所以在以上的情况下,需要在init之前调用openDebug
TransformException:java.util.zip.ZipException: duplicate entry …
ARouter有按组加载的机制,关于分组可以参考 6-1 部分,ARouter允许一个module中存在多个分组,但是不允许多个module中存在相同的分组,会导致映射文件冲突
Kotlin类中的字段无法注入如何解决?
首先,Kotlin中的字段是可以自动注入的,但是注入代码为了减少反射,使用的字段赋值的方式来注入的,Kotlin默认会生成set/get方法,并把属性设置为private 所以只要保证Kotlin中字段可见性不是private即可,简单解决可以在字段上添加 @JvmField
通过URL跳转之后,在intent中拿不到参数如何解决?
需要注意的是,如果不使用自动注入,那么可以不写 ARouter.getInstance().inject(this)
,但是需要取值的字段仍然需要标上 @Autowired
注解,因为 只有标上注解之后,ARouter才能知道以哪一种数据类型提取URL中的参数并放入Intent中,这样您才能在intent中获取到对应的参数
新增页面之后,无法跳转?
ARouter加载Dex中的映射文件会有一定耗时,所以ARouter会缓存映射文件,直到新版本升级(版本号或者versionCode变化),而如果是开发版本(ARouter.openDebug()), ARouter 每次启动都会重新加载映射文件,开发阶段一定要打开 Debug 功能
enDebug/openLog), 查看映射表是否已经被扫描出来,形如 D/ARouter::: LogisticsCenter has already been loaded, GroupIndex[4],GroupIndex > 0
ARouter开启InstantRun之后无法跳转(高版本Gradle插件下无法跳转)?
因为开启InstantRun之后,很多类文件不会放在原本的dex中,需要单独去加载,ARouter默认不会去加载这些文件,因为安全原因,只有在开启了openDebug之后 ARouter才回去加载InstantRun产生的文件,所以在以上的情况下,需要在init之前调用openDebug
TransformException:java.util.zip.ZipException: duplicate entry …
ARouter有按组加载的机制,关于分组可以参考 6-1 部分,ARouter允许一个module中存在多个分组,但是不允许多个module中存在相同的分组,会导致映射文件冲突
Kotlin类中的字段无法注入如何解决?
首先,Kotlin中的字段是可以自动注入的,但是注入代码为了减少反射,使用的字段赋值的方式来注入的,Kotlin默认会生成set/get方法,并把属性设置为private 所以只要保证Kotlin中字段可见性不是private即可,简单解决可以在字段上添加 @JvmField
通过URL跳转之后,在intent中拿不到参数如何解决?
需要注意的是,如果不使用自动注入,那么可以不写 ARouter.getInstance().inject(this)
,但是需要取值的字段仍然需要标上 @Autowired
注解,因为 只有标上注解之后,ARouter才能知道以哪一种数据类型提取URL中的参数并放入Intent中,这样您才能在intent中获取到对应的参数
新增页面之后,无法跳转?
ARouter加载Dex中的映射文件会有一定耗时,所以ARouter会缓存映射文件,直到新版本升级(版本号或者versionCode变化),而如果是开发版本(ARouter.openDebug()), ARouter 每次启动都会重新加载映射文件,开发阶段一定要打开 Debug 功能