Android开发----移植华为java工程+高德地图实现自己的一个应用

版权声明:本文为博主原创文章,未经博主允许不得转载。https://github.com/SCFMVP https://blog.csdn.net/qq_37832932/article/details/82722049

 新手, 花了一周时间做出来的, 遇到很多坑, 如有不足请多指教.

 项目地址: github


一. 移植华为给的java工程

 在华为的OceanConnect上下载java的Demo, 待会我们把工程文件直接复制到我们新建的AS工程下面去. (我只用到了一个接口, 但是每个接口修改调用都是一样的)

复制所需文件:

Huawei_IoT_Platform_Demo_North_Lite\LiteNAdemo_https\src\com\huawei 目录下的所有文件夹

Huawei_IoT_Platform_Demo_North_Lite\LiteNAdemo_https\Open source components 目录下的jar包

Huawei_IoT_Platform_Demo_North_Lite\LiteNAdemo_https\src\resource 目录下的证书文件

工程配置:

 右击lib目录下的jar包  ->   add as library

gridle配置: 

 src目录下的build.grdle: 

出现问题如下: 

/*
    Error:duplicate files during packaging of APK E:\AndroidStudioProjects\huawei\NADemo\app\build\outputs\apk\app-debug-unaligned.apk
   Path in archive: META-INF/DEPENDENCIES
   Origin 1: E:\AndroidStudioProjects\huawei\NADemo\app\libs\httpmime-4.5.2.jar
   Origin 2: E:\AndroidStudioProjects\huawei\NADemo\app\libs\httpcore-4.4.4.jar
You can ignore those files in your build.gradle:
   android {
     packagingOptions {
       exclude 'META-INF/DEPENDENCIES'
     }
   }
    */
解决方法: 
    //兼容一些版本较旧的包
    packagingOptions {
        exclude 'META-INF/DEPENDENCIES.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/dependencies.txt'
        exclude 'META-INF/LGPL2.1'
    }

 修改Constant类:

 这里就是OceanConnect应用的一些配置修改为自己应用的参数.

主要是:

//please replace the IP and Port, when you use the demo.
public static final String BASE_URL = "https://ip:8743";

//please replace the appId and secret, when you use the demo.
public static final String APPID = "'''''''''''";
public static final String SECRET = "''''''''''";

然后我开始编译这个工程, 发现在eclipse下运行可以获取到数据, 但是AS下试报错的. 报错有两方面.

  •  一方面是原本在eclipse下可以用的方法, 在AS里却标红(不知道是什么原因), 我在网上查了一些资料最终还是解决了, 具体解决可以参考我的代码
  •  另一方面是非继承Activity的类是不可以去访问AS工程目录下的资源文件的, 所以我想了办法先在Activity中把文件复制到手机的指定位置, 然后非继承Activity类就去访问这个位置就好了

 修改HttpUtil类

 修改如下: sunx509改为x509, SSLSocketFactory方法的调用, httpclient的register, 不再使用 URIBuilder

//TODO : url替换
	/**
	 * Two-Way Authentication In the two-way authentication, the client needs: 1
	 * Import your own certificate for server verification; 2 Import the CA
	 * certificate of the server, and use the CA certificate to verify the
	 * certificate sent by the server; 3 Set the domain name to not verify
	 * (Non-commercial IoT platform, no use domain name access.)
	 * */
	public void initSSLConfigForTwoWay() throws Exception {
		// 1 Import your own certificate
		String demo_base_Path = System.getProperty("user.dir");
		String selfcertpath = Constant.SELFCERTPATH; //demo_base_Path + Constant.SELFCERTPATH;   //   69-73
		String trustcapath = Constant.TRUSTCAPATH; // demo_base_Path + Constant.TRUSTCAPATH;     //

		KeyStore selfCert = KeyStore.getInstance("pkcs12");
		String sdCardDir = Environment.getExternalStorageDirectory().getAbsolutePath();  //把文件放在SD根目录
		//File file = new File(sdCardDir + "/a.txt");
		selfCert.load(new FileInputStream(sdCardDir+"/outgoing.CertwithKey.pkcs12"),//-------wenjian
				Constant.SELFCERTPWD.toCharArray());
		KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");    //sunx509
		kmf.init(selfCert, Constant.SELFCERTPWD.toCharArray());

		// 2 Import the CA certificate of the server,
		KeyStore caCert = KeyStore.getInstance("bks");   //jks
		caCert.load(new FileInputStream(sdCardDir+"/ca.bks"), Constant.TRUSTCAPWD.toCharArray());//----------wenjian
		TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
		tmf.init(caCert);

		SSLContext sc = SSLContext.getInstance("TLS");
		sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

		// 3 Set the domain name to not verify
		// (Non-commercial IoT platform, no use domain name access generally.)
		//SSLSocketFactory ssf = new SSLSocketFactory(selfCert,Constant.SELFCERTPWD, caCert);
		SSLSocketFactory ssl = new SSLSocketFactory(selfCert, Constant.SELFCERTPWD, caCert);
		ssl.setHostnameVerifier(new AllowAllHostnameVerifier());
		//SSLConnectionSocketFactory scsf=new SSLConnectionSocketFactory(sc, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
		// If the platform has already applied for a domain name which matches
		// the domain name in the certificate information, the certificate
		// domain name check can be enabled (open by default)
		//SSLSocketFactory ssf = new SSLSocketFactory(sc);

		//ClientConnectionManager ccm = this.getConnectionManager();
		//SchemeRegistry sr = ccm.getSchemeRegistry();
		//sr.register(new  Scheme("https", ssl, 8743));//有修改

		httpClient = new DefaultHttpClient();
		if (ssl != null) {
			Scheme sch = new Scheme("https", ssl, 8743);
			httpClient.getConnectionManager().getSchemeRegistry().register(sch);
		}
	}

 调用接口:

 最后一步就是调用接口获取数据了, 在java的工程里每一个接口都是static main方法, 我们把他改成普通方法并调用就可以了

调用示例:

QueryDeviceData qd = new QueryDeviceData();
String msg = qd.hello(Constant.xxx);

二. 使用高德地图

 调用高德地图主要是定位, 标记点 (附近派单功能开发过程中调用失败)

高德地图调用并不难, 文档说的也很清楚: https://lbs.amap.com/api/android-sdk/guide/create-map/show-map

 这里也贴出我调用的代码:

显示基本地图:

 /**
  * 显示基本地图
  */
mapView = (MapView) findViewById(R.id.map);
mapView.onCreate(savedInstanceState);// 此方法须覆写,虚拟机需要在很多情况下保存地图绘制的当前状态。The specified child already has a parent. You must call removeView() on the child's parent first
//初始化地图控制器对象
showMap();

定位的实现:

/**
 * 不显示缩放浮标, 定位按钮显示
 */
mUiSettings = aMap.getUiSettings();//实例化UiSettings类对象
mUiSettings.setZoomControlsEnabled(false);
//aMap.setLocationSource(this);//通过aMap对象设置定位数据源的监听
mUiSettings.setMyLocationButtonEnabled(true); //显示默认的定位按钮
mUiSettings.setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_CENTER);//底部居中
aMap.setMyLocationEnabled(true);// 可触发定位并显示当前位置

定位蓝点

/**
 * 定位蓝点Style的实现
 */
MyLocationStyle myLocationStyle;
myLocationStyle = new MyLocationStyle();//初始化定位蓝点样式类myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);//连续定位、且将视角移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。(1秒1次定位)如果不设置myLocationType,默认也会执行此种模式。
myLocationStyle.strokeColor(Color.BLACK);//设置定位蓝点精度圆圈的边框颜色的方法。
myLocationStyle.radiusFillColor(Color.argb(100, 0, 0, 180));//设置定位蓝点精度圆圈的填充颜色的方法。
        myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_FOLLOW_NO_CENTER);//连续定位、蓝点不会移动到地图中心点,定位点依照设备方向旋转,并且蓝点会跟随设备移动。
myLocationStyle.interval(2000); //设置连续定位模式下的定位间隔,只在连续定位模式下生效,单次定位模式下不会生效。单位为毫秒。
aMap.setMyLocationStyle(myLocationStyle);//设置定位蓝点的Style
aMap.getUiSettings().setMyLocationButtonEnabled(true);//设置默认定位按钮是否显示,非必需设置。
aMap.getMinZoomLevel();
aMap.setMyLocationEnabled(true);// 设置为true表示启动显示定位蓝点,false表示隐藏定位蓝点并不进行定位,默认是false。

打点方法:

/**
 * 打点
 * tip: LatLan 在 Constant类
 */
    public void addMarker(double lng,double lat, String title,String context,int status){ //通用类
        if(status==0) {
            aMap.addMarker(new MarkerOptions().position(new LatLng(lng, lat))
                    .title(title).icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory
                            .decodeResource(getResources(), R.drawable.trash_unfull))).snippet(context));
        }
        else if(status==1){
            aMap.addMarker(new MarkerOptions().position(new LatLng(lng, lat))
                    .title(title).icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory
                            .decodeResource(getResources(), R.drawable.trash_full))).snippet(context));
        }
    }

消除点方法:

   /**
     * --清除所有点
     * --使用需小心 !!! ---- 触发使用, 用完刷新 !!!
     * --UI线程
     */
    public void clearAllMarker(){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                aMap.clear();
            }
        });
        Log.d("111","clearAllMarker over");
    }

地图回调方法

@Override
protected void onDestroy(){
     super.onDestroy();//在activity执行onDestroy时执行mMapView.onDestroy(),销毁地图
     mMapView.onDestroy();
}
@Override
protected void onResume(){
     super.onResume();//在activity执行onResume时执行mMapView.onResume (),重新绘制加载地图
     mMapView.onResume();
}
@Override
protected void onPause(){
     super.onPause();//在activity执行onPause时执行mMapView.onPause (),暂停地图的绘制
     mMapView.onPause();
}
@Override
protected void onSaveInstanceState(Bundle outState){
     super.onSaveInstanceState(outState);//在activity执行onSaveInstanceState时执行        mMapView.onSaveInstanceState (outState),保存地图当前的状态
     mMapView.onSaveInstanceState(outState); 
}

 这边都仅仅是局部代码, 具体的参考工程

三. UI界面设计

 UI界面分为五个部分

登录部分

 我使用的就是AS自带的登录Activity, 这里不需要过多说明, 设置好登录正确进入主页就好了

地图主页

 这里调用高德地图, 通过Marker显示信息

信息发送

 这里也是小儿科的电话, 短信, qq, 微信的启动

任务列表

 通过OceanConnect接口查询, 显示一个自定义的Listview, 这里太长就不贴代码.

个人中心

 参照CSDN某篇博客摸索出来的, 效果还不错

四. 可能遇到的问题

ui线程 : 这里是我掉进去最多的坑, 更新Ui请务必在主线程中进行 !!!! !!!!!!! !!!!!!! !!!!!!!

调用方法:

 1. runOnUiThread()

runOnUiThread(new Runnable() {
            @Override
            public void run() {
                aMap.clear();
            }
        });

2. handler.post ()

handler.post(new Runable()){
            @Override
            public void run() {
                aMap.clear();
            }
        });

线程死循环

 这应该是基础了吧, 我还是掉进来了, 花了好长时间才恍然大悟, 我忘记了while还想让他轮询

new Thread(new Runnable(){
            @Override
            public void run() {
                while(true) {     //竟然忘了这个!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    //休眠线程
                    try {
                        //do something
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        Log.d("111", "线程意外失效! ");
                    }
                }
            }
        }).start();

网络线程

还有一个就是我们调用OceanConnect的接口获取数据是一个网络请求, 最好单独开一个线程, 以防阻塞. 不建议用别的方法.

作为菜鸟分享一个安卓开发的好方法: 在出现错误调试的时候, 在每个节点加上Log.d(); 这样问题出现在什么地方会更容易发现, 是不是还要debug方法我不知道. 我目前用的都是Log排错.

五. 实现效果

 

 

猜你喜欢

转载自blog.csdn.net/qq_37832932/article/details/82722049