zoukankan      html  css  js  c++  java
  • 移动开发多平台代码共享

     做移动开发快一年了,有幸接触了WMSymbianAndroidiPhone等多个平台的开发。往往一个软件需要实现多个平台的版本,对于不同平台进行重新编码是一件很费劲的事情,其实我们可以通过代码共用技术,实现对一些代码的重用。

          这一技术的应用,可以带来不少的好处:

    1.代码重用:节约开发和维护的时间

    2.核心代码的保护:将核心代码编译成库,只将库而不是源代码提供给上层开发人员使用。

    3.。。。。。。

          本文将实现一个支持这几个平台的天气信息查询软件,软件采用C语言去实现调用WebService接口获取天气信息的功能,并将其编译成各种平台能够调用的库,而UI则采用各个平台各自的语言去实现,最终实现底层代码的共用。

    先来看看最终的效果图:

    一、底层代码的实现

    我们要调用到WebService接口,需要使用网络

    而对于不同的平台socket的使用上有细微差异,我通过条件编译的方式,实现对不同平台的兼容。

    下面是实现代码:

    复制代码
    //对于VC的DLL,需要导出函数,而其他的则不需要
    头文件Common.h
    #ifdef _MSC_VER
    #define DLLFLAG _declspec(dllexport)
    #else
    #define DLLFLAG ""
    #endif
    //通过WebService接口获取天气信息
    DLLFLAG char* getWeather(constchar*cityName);
    源文件Common.c
    #include
    <string.h>
    #include
    <Common.h>
    #include
    <stdlib.h>
    //根据系统加载不同的网络库
    #ifdef _MSC_VER
    #include
    <winsock2.h>
    #pragma comment(lib, "winsock.lib")
    #else
    #include
    <sys/socket.h>
    #include
    <netinet/in.h>
    #include
    <arpa/inet.h>
    #include
    <netdb.h>
    #endif
    #define BUFSIZ 4096
    DLLFLAG
    char* getWeather(constchar*pCityName)
    {
    //对于VC需要初始化socket版本
    #ifdef _MSC_VER
    WSADATA wsaData;
    int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
    #endif
    int sockfd =0;
    struct sockaddr_in addr;
    char text[BUFSIZ] ="";
    char header[BUFSIZ] ="";
    char*content = (char*)malloc(BUFSIZ);
    sockfd
    = socket(AF_INET, SOCK_STREAM, 0);
    addr.sin_family
    = AF_INET;
    //不同平台填充地址字段的方式不同
    #ifdef _MSC_VER
    addr.sin_addr.S_un.S_addr
    =inet_addr("222.73.218.218");
    #else
    inet_aton(
    "222.73.218.218",&addr.sin_addr);
    #endif
    addr.sin_port
    = htons(80);
    memset(header,
    0, sizeof(header));
    strcat(header,
    "GET /Service.asmx/getWeatherbyCityName?theCityName=");
    strcat(header, pCityName);
    strcat(header,
    "&theDayFlag=Today HTTP/1.1rn");
    strcat(header,
    "Host: www.ayandy.comrnrn");
    connect(sockfd,(
    struct sockaddr *)&addr,sizeof(struct sockaddr_in));
    send(sockfd, header, strlen(header),
    0);
    memset(text,
    0, BUFSIZ);
    memset(content,
    0, BUFSIZ);
    recv(sockfd, text, BUFSIZ,
    0);
    strcat(content, text);
    //while ( recv(sockfd, text, BUFSIZ, 0) > 0)
    //{
    // strcat(content, text);
    // memset(text, 0, BUFSIZ);
    //}
    //不同平台关闭socket的方法不同
    #ifdef _MSC_VER
    closesocket(sockfd);
    WSACleanup();
    #else
    shutdown(sockfd, SHUT_RDWR);
    #endif
    return content;
    }
    复制代码






     

    二、Windows Mobile 平台

    对于WM平台,为了与底层库相区别,我们就不用VC去实现UI,而使用C#来实现UI

    1.编译dll

    Visual C++  – 智能设备 – 由于没有好的dll模板,我们就建一个“MFC智能设备DLL”

    取名ShareLib,然后在生成的项目中删除掉没用的文件(比如预编译啥的),添加我们的底层代码文件Common.h和 Common.c,最终文件结构如图:

    然后编译,最终会生成ShareLib.dll文件

    2.实现主界面

    新建一个C#的智能设备项目,取名ShareLibTest


    Form1.cs文件中,添加对于dll的引用

    [DllImport(@"ShareLib.dll",CharSet=CharSet.Unicode) ]
    public static extern IntPtr getWeather(string cityName);

     

    然后进行界面的设计,最终界面如图:

    然后给按钮设置点击事件:

    try
    {
        byte[] paraByte = Encoding.UTF8.GetBytes(txtLocation.Text);
     IntPtr p = getWeather(Encoding.Unicode.GetString(paraByte, 0, paraByte.Length));
     string newWeather = Marshal.PtrToStringUni(p);
     byte[] strByte = Encoding.Unicode.GetBytes(newWeather);
     newWeather = Encoding.UTF8.GetString(strByte, 0, strByte.Length);
     int a = newWeather.IndexOf("/>");
     int b = newWeather.IndexOf("http://");
        int aLength = "/>".Length;
        newWeather = newWeather.Substring(a + aLength, b - a - aLength);
     newWeather = newWeather.Replace("", "").Replace("", "");
        txtWeatherInfo.Text = newWeather;
    }
    catch (System.Exception )
    {
    }

    代码中关键的一句就是使用Marshal完成从cchar* 转换为C#string,还有,需要注意字符的编码,否则可能会导致获取的数据乱码。

    最终,运行程序就能看到效果了。

    三、Android平台

    1.编译so

    对于Android平台,我们用Java实现UI

    java中,要调用C/C++,需要使用jni技术

    我们先写一个javaJniTest.java

    代码如下:

    public class JniTest {
        public native String getWeather(String cityNmae);
    }

    然后打开命令提示符:

    //输入:
    javac JniTest.java
    //然后输入:
    javah -jni com.luzj.ShareLibTest.JniTest
     
     

    最终就会产生com_luzj_ShareLibTest_JniTest.h 文件,复制一份,将后者改为.c

    打开com_luzj_ShareLibTest_JniTest.c文件,通过#include ”Common.h” 引入底层代码

    然后去实现那个getWeather函数,在这个函数中主要完成对javaStringCchar*的相互转换工作,代码如下:

    const char* name = (*env)->GetStringUTFChars(env, cityName, 0); 
    const char *cWeatherInfo = getWeather( name );
    jstring weatherInfo = (*env)->NewStringUTF(env, cWeatherInfo);
    (*env)->ReleaseStringUTFChars(env,cityName,name);  
    return weatherInfo;
     

    然后编写一个make文件Android.mk,代码如下:

    LOCAL_PATH:= http://www.cnblogs.com/lib
    include $(CLEAR_VARS)
    LOCAL_MODULE    := JniTest
    LOCAL_SRC_FILES := com_luzj_ShareLibTest_JniTest.c Common.c
    include $(BUILD_SHARED_LIBRARY)
     

    最后,使用NDK-build一下,就会生成Android可用的动态链接库.so文件了

    2.实现主界面

    没啥好说的,对于开发过Android的人都能做到

    然后在Activity中通过代码加载动态链接库

    //加载c库
    static {
    System.loadLibrary(
    "JniTest");
    }

    最后在要获取天气数据的地方调用JniTest类的中的getWeather方法即可

     

    四、iPhone平台

    iPhone平台,对于UI,使用Obj-C来实现。

    iPhone平台上,我们可以将公用代码编译成静态库然后给程序调用。

    1.编译静态库

    首先,通过“Cocoa Touch Static Library”创建一个静态库的工程

    将我们的底层库添加上去,编译一下,就会生成一个以“.a”为后缀的静态库了

    2.实现主界面

    拉个按钮到界面上去,给它添加事件

    主要代码就下面两行,完成了NSString 与 char* 的相互转化,并调用了接口

     

    char* strWeatherInfo = getWeather([txtLocation.text UTF8String]);
    NSString
    *weatherInfo = [NSString stringWithUTF8String:strWeatherInfo];
     

    最后将数据显示到界面上即可

    五、Symbian平台

    我始终对这个平台没啥好感,况且这个平台的开发本身就是使用CC++,实现代码共用很容易的,在此我就不浪费笔墨了,有兴趣的自己试试。

     

    六、总结

    这一技术还是很有使用前景的,比如游戏开发者,可用通过代码共用,用Open GL 实现一个底层的游戏引擎给各个平台使用。

    由于时间的关系,代码中对于异常的处理和一些条件的判断都没有去做,有兴趣的同学自己完善!

    文章中的Demo已经打包,需要的可以自行下载。

    下载地址:http://u.115.com/file/dn69hko2

    在我的独立博客还有一些好文章,有兴趣的可以去看看:http://luzj.me/share-lib-test-mobil.html

  • 相关阅读:
    Java:Excel文件上传至后台
    JDK1.8中的HashMap实现
    Redis远程连接报错解决
    Redis操作命令总结
    HashMap实现原理及源码分析
    谈谈对Spring IOC的理解
    centos 7.3 服务器环境搭建——MySQL 安装和配置
    Linux系统下 docker安装命令
    JS求两个数组的交集 (假设数组已经经过排序)
    作用域和作用域链
  • 原文地址:https://www.cnblogs.com/zhwl/p/2788733.html
Copyright © 2011-2022 走看看