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

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

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

      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(const char *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(const char *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完成从c的char* 转换为C#的string,还有,需要注意字符的编码,否则可能会导致获取的数据乱码。

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

      三、Android平台

      1. 编译so

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

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

      我们先写一个java类JniTest.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函数,在这个函数中主要完成对java的String和C的char*的相互转换工作,代码如下:

    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平台

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

      六、总结

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

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

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

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

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

  • 相关阅读:
    软件测试人员的年终绩效考核怎么应对
    收藏
    顶踩组件 前后两版
    订阅组件
    hdu 1963 Investment 完全背包
    hdu 4939 Stupid Tower Defense 动态规划
    hdu 4405 Aeroplane chess 动态规划
    cf 414B Mashmokh and ACM 动态规划
    BUPT 202 Chocolate Machine 动态规划
    hdu 3853 LOOPS 动态规划
  • 原文地址:https://www.cnblogs.com/waw/p/2164442.html
Copyright © 2011-2022 走看看