安卓问题-第三方相关

第三方相关问题

分享相关

关于微信无法分享问题

前置条件:使用友盟第三方分享(包含了微信)
排查步骤:

  1. 看日志
    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

微信支付调用不起来的问题(AsyncTask的坑).png

WXPayEntryActivity 不回调问题
  1. 注意包名:平台注册的包名+.wxapi.WXPayEntryActivity (完整com.xxx.wxapi.WXPayEntryActivity)
  2. 注意类名 WXPayEntryActivity 不能写错,在清单文件中进行注册
  3. 在清单文件中检查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.javaonCreate中用了自定义的super.onCreate(savedInstanceState, R.layout.activity_wxpay_entry, R.layout.title_default);改成系统的super.onCreate(savedInstanceState);即可

微信支付:弹起支付页面但是原来的页面走了onPause没有走onStop方法

命令adb shell dumpsys activity | findstr Run查看当前运行的Activity

调微信支付本身页面不走onStop.png

猜测com.tencent.mm/.plugin.wallet_index.ui.OrderHandlerUI是个Activity当成加载的loading(dialog),此时底部的PayActivity还处于可见状态(调起onPause()),之后OrderHandlerUI自身又调起com.tencent.mm/.framework.app.UIPageFragmentActivity这个Activity,使得PayActivity不可见

UIPageFragmentActivityPayActivity不是相邻的(中间隔了一个OrderHandlerUI)所以影响不到PayActivity的生命周期,即不会触发PayActivityonStop方法

微信WAP支付提示”商家参数格式有误,请联系商家解决"

问题:安卓webView内的外部商家开发的链接,点立即购买后调起微信这一步出现“商家参数格式有误,请联系商家解决”

解决:找到微信官方给出的文档

另外参考另一篇解决方案

WebViewshouldOverrideUrlLoading内加上

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 遇到的问题

  1. Duplicate zip entry[classes.jar:com/ut/device/UTDevice.class]

原因:支付 sdk 和友盟 sdk 都有这个文件

解决:支付 sdk 下载个不再 utdevice 的 aar 包

  1. 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,别坚信文档!!!(豹奔–膳闯项目)

  1. android端,本地不做预下单(不安全)。预下单是后台做的。查询订单也是后台的。android端做的:接收后台提供的token_id,并结合微信appid调起支付的sdk就ok了(注意在注册清单文件中对应页面的Activity里要写上这个微信appid)

  2. 后台的坑:appid要改成sub_appid,demo和文档要结合着来看。

支付宝支付

集成支付宝支付出现{resultStatus=4000, result=, memo=系统繁忙,请稍后再试}

  1. {resultStatus=4000, result=, memo=系统繁忙,请稍后再试}

    如果APPID,PID,TARGET_ID,RSA2_PRIVATE都正确的情况下,看手机是否已安装支付宝应用

  2. {resultStatus=4000, result={“alipay_trade_app_pay_response”:{“code”:“40006”,“msg”:“Insufficient Permissions”,“sub_code”:“isv.insufficient-isv-permissions”,“sub_msg”:“ISV权限不足,建议在开发者中心检查应用是否上线”}}, memo=}

    应用没有上线的原因

第三方登录

友盟 微信登录授权不走回调

问题:微信登录没有获取到用户信息、没有反应

解决:

  1. 确认能否进入微信客户端授权确认页面

如果不能进入微信授权页面,或者在微信客户端账号未登录状态下只能进入输入账号密码页面,说明签名验证失败,请检查签名是否一致。

  1. 进入微信授权确认页面,点击后没有返回对应的用户资料

进入这一步多半是由于微信回调配置错误导致,首先打开 Debug 模式日志,查看回调Activity(WXEntryActivity.java) 配置是否正常。

如果确认回调 Activity 及AndroidManifest.xml中微信相关配置都正确,需要确认 WXEntryActivity.java中有无复写其他 SDK(如支付、微信原生登录)的回调逻辑,UShare SDK要求留一个空类,相关回调结果在jar中实现,如微信精简版中 Demo 里的配置:

public class WXEntryActivity extends WXCallbackActivity{}

推送

关于友盟无法推送问题

  • 排查步骤:

    1. ios和安卓是否都不可以,排查是否是后台问题
    2. 看参数,是否加IP白名单
      2.1. 看gradle中配置的参数、看友盟控制台配置的参数、看后台配置的参数(注意正式线还是测试线)
      2.2. 在友盟控制台模拟发送,(从AS取友盟Token)发送给特定用户
    3. ios证书是否配置了
  • 又一城安卓友盟推送问题排查步骤

    1. 确认安卓和ios是否单端出现问题,如果单端出现问题,那么大概率是APP端的问题,需要各自排查问题;

    2. 单端出现问题的情况下,需要先排查与友盟的对接是否出现问题,先在友盟的后台通过推送测试消息,
      可同时测试独立用户(设备码)和特定用户(别名),如果无法推送成功,那么就是与友盟的对接出现了问题,需要排查参数的配置是否出错;

    3. 排查参数配置时需要排查代码、友盟后台、后台的AppKey、MasterSecret、MessageSecret的参数配置,
      IOS还需要排查证书;其中后台的配置地址为:
      后台顾客端参数配置:域名/weChat/appGenerationSuccess
      后台导购端参数配置:域名/appPackage/guideAppGenerationSuccess
      如果参数配置没有问题,通过友盟后台推送还是失败,那可能是代码中出现错误;

    4. 在双端友盟推送能够成功,并且在确定各端友盟对应应用已配置了IP白名单(IP为域名对外访问对应的IP。比如阿里云给的IP)的情况下
      (注:需要确定友盟控制台已添加IP白名单)在确定白名单已经配置的情况下,
      Android端和IOS端会同时出现问题,那么大概率可能是后台的问题,需要告知后台帮忙排查解决问题

    5. 推送失败信息如下:
      什么是DeviceTokenNotForTopic

      • DeviceToken和当前的bundleID不匹配
        一般是推送证书有问题,需要重新上传证书。
        注:在项目未发布的时候就要针对推送进行测试,及时发现问题并解决,如果发现了推送问题,可参照以上的步骤进行排查
    6. 关于友盟后台推送可以收到,又一城后台推送收不到

      1. 排查参数:查看友盟后台登记的参数、app中的参数、又一城后台登记的第三方参数(注意:**有可能message和secret参数顺序填反**)
      2. 排查友盟后台是否有填IP白名单
      

友盟注册报错 s=-11,s1=accs bindapp error

排查:

  1. 检查参数、IP白名单、后台填的参数
  2. 代码中注册逻辑要加mPushAgent.setResourcePackageName(packageName);
  3. 有可能是跟阿里百川一起使用,导致的冲突(有可能是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中添加参数

ResClass未初始化的解决1.png

2、在调用这个注册的地方添加参数

ResClass未初始化的解决2.png

3、注意这个packageName要与AndroidManifest.xml中的包名一致

ResClass未初始化的解决3.png

ResClass未初始化的解决4.png

后台推送消息,手机接收不到的问题

排查过程:

  1. 先对比ios和安卓看两端是否有同样问题

    1. 如果有同样问题,检查参数配置(友盟控制台、手机端、后台)要一致、友盟控制台的IP白名单是否配置
  2. 因为ios未上架AppStore无法推送,排除与ios对比的可能性,从参数、ip白名单等方面排查

  3. 检查参数(友盟控制台、后台、安卓端)一致,尝试从友盟控制台推送消息,安卓可接收到【得出参数无误的结论】

  4. 检查友盟控制台IP白名单,无误【得出不是IP白名单问题】

  5. 通过后台网页发送推送消息,后台服务抓取参数进行比对,发现友盟注册别名"alias_type"错误

  6. 别名错误的原因是groovy中设置的“\\”导致首字母消失【详解见 https://shenbh.top/gradle知识/Gradle笔记/下的groovy的manifestPlaceholders属性值取值问题 这个笔记】

IM即时通讯

关于百川IM在安卓8不能调起问题(阿里已经不维护了)

现象:PMS顾客端IM聊天在安卓8不能调起,会报登录超时。安卓8以下的正常。导购端的都正常(包括在安卓8)
排查步骤:

  1. 排查是否是tcmService进程没有开启(在AS的logcat的标题栏上看的)
  2. 排查gradle中的targetVersion的值,IM不支持太高的版本(解决:降低targetVersion)
    原因:辣苹果顾客端targetVersion设置成27,而云旺不支持这么高的版本。
    解决:降低targetVersion

百川在安卓8以上无法推送问题

现象:导购端退到后台,顾客端发送消息。在安卓6上导购端状态栏有新消息提示,在安卓8以上没有新消息提示

解决:【暂不解决,百川都不维护了,看看客户是否换成融云】

地图&定位

高德地图相关

key、定位相关
  1. 如果误删高德地图控制台申请的应用和key
    可以进行添加新的key,同时要更改代码注册清单文件中对应的apikey的值
  2. 同一个应用可以申请多个key,不过注册清单文件中的apikey只能一个,所以限制了只能有一个生效
    (当然如果是两个编辑器进行编译的话,那么可以同时用到两个)
  3. 高德地图控制台申请应用名,即使删除了也不能重新用这个名字
  4. 注意:在安卓6.0以上的sdk中,权限是要写在代码中,在注册清单文件中写的无效。(只能在手机的设置里信任此应用方可),否则会报“缺少定位权限”的异常
  5. 删除了高德地图控制台申请的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);
	}
}

百度定位移到项目中不可用

  1. 检查权限;检查是不是重新申请了key(一个包名对应一个key);
  2. 用百度定位的时候要用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][ ]”

  • 通常来说这种情况是没有找到目标页面,目标不存在
  • 如果这个页面是存在的,那么您可以按照下面的步骤进行排查
    1. 检查目标页面的注解是否配置正确,正确的注解形式应该是 (@Route(path="/test/test"), 如没有特殊需求,请勿指定group字段,废弃功能)
    2. 检查目标页面所在的模块的gradle脚本中是否依赖了 arouter-compiler sdk (需要注意的是,要使用apt依赖,而不是compile关键字依赖)
    3. 检查编译打包日志,是否出现了形如 ARouter::�Compiler >>> xxxxx 的日志,日志中会打印出发现的路由目标
    4. 启动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 功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值