找回密码
 立即注册
首页 业界区 业界 移动开发多平台代码共享

移动开发多平台代码共享

归悦可 2025-5-29 15:45:36
     做移动开发快一年了,有幸接触了WM、Symbian、Android、iPhone等多个平台的开发。往往一个软件需要实现多个平台的版本,对于不同平台进行重新编码是一件很费劲的事情,其实我们可以通过代码共用技术,实现对一些代码的重用。
      这一技术的应用,可以带来不少的好处:
1.代码重用:节约开发和维护的时间
2.核心代码的保护:将核心代码编译成库,只将库而不是源代码提供给上层开发人员使用。
3.。。。。。。
      本文将实现一个支持这几个平台的天气信息查询软件,软件采用C语言去实现调用WebService接口获取天气信息的功能,并将其编译成各种平台能够调用的库,而UI则采用各个平台各自的语言去实现,最终实现底层代码的共用。
先来看看最终的效果图:
1.jpeg

2.jpeg

3.jpeg

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





二、Windows Mobile 平台
对于WM平台,为了与底层库相区别,我们就不用VC去实现UI,而使用C#来实现UI。
1.编译dll
Visual C++  – 智能设备 – 由于没有好的dll模板,我们就建一个“MFC智能设备DLL”,
4.jpeg

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

然后编译,最终会生成ShareLib.dll文件
2.实现主界面
新建一个C#的智能设备项目,取名ShareLibTest
6.jpeg


在Form1.cs文件中,添加对于dll的引用
  1. [DllImport(@"ShareLib.dll",CharSet=CharSet.Unicode) ]
  2. public static extern IntPtr getWeather(string cityName);
复制代码

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

然后给按钮设置点击事件:
  1. try
  2. {
  3.     byte[] paraByte = Encoding.UTF8.GetBytes(txtLocation.Text);
  4. IntPtr p = getWeather(Encoding.Unicode.GetString(paraByte, 0, paraByte.Length));
  5. string newWeather = Marshal.PtrToStringUni(p);
  6. byte[] strByte = Encoding.Unicode.GetBytes(newWeather);
  7. newWeather = Encoding.UTF8.GetString(strByte, 0, strByte.Length);
  8. int a = newWeather.IndexOf("/>");
  9. int b = newWeather.IndexOf("http://");
  10.     int aLength = "/>".Length;
  11.     newWeather = newWeather.Substring(a + aLength, b - a - aLength);
  12. newWeather = newWeather.Replace("", "").Replace("", "");
  13.     txtWeatherInfo.Text = newWeather;
  14. }
  15. catch (System.Exception )
  16. {
  17. }
复制代码
代码中关键的一句就是使用Marshal完成从c的char* 转换为C#的string,还有,需要注意字符的编码,否则可能会导致获取的数据乱码。
最终,运行程序就能看到效果了。
三、Android平台
1.编译so
对于Android平台,我们用Java实现UI。
在java中,要调用C/C++,需要使用jni技术
我们先写一个java类JniTest.java
代码如下:
  1. public class JniTest {
  2.     public native String getWeather(String cityNmae);
  3. }
复制代码
然后打开命令提示符:
  1. //输入:
  2. javac JniTest.java
  3. //然后输入:
  4. 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*的相互转换工作,代码如下:
  1. const char* name = (*env)->GetStringUTFChars(env, cityName, 0);
  2. const char *cWeatherInfo = getWeather( name );
  3. jstring weatherInfo = (*env)->NewStringUTF(env, cWeatherInfo);
  4. (*env)->ReleaseStringUTFChars(env,cityName,name);  
  5. return weatherInfo;
复制代码

然后编写一个make文件Android.mk,代码如下:
  1. LOCAL_PATH:= http://www.cnblogs.com/lib
  2. include $(CLEAR_VARS)
  3. LOCAL_MODULE    := JniTest
  4. LOCAL_SRC_FILES := com_luzj_ShareLibTest_JniTest.c Common.c
  5. include $(BUILD_SHARED_LIBRARY)
复制代码

最后,使用NDK-build一下,就会生成Android可用的动态链接库.so文件了
2.实现主界面
没啥好说的,对于开发过Android的人都能做到
然后在Activity中通过代码加载动态链接库
  1.     //加载c库  <br>    static {<br>        System.loadLibrary("JniTest");<br>    }
复制代码
最后在要获取天气数据的地方调用JniTest类的中的getWeather方法即可


四、iPhone平台
在iPhone平台,对于UI,使用Obj-C来实现。
在iPhone平台上,我们可以将公用代码编译成静态库然后给程序调用。
1.编译静态库
首先,通过“Cocoa Touch Static Library”创建一个静态库的工程

将我们的底层库添加上去,编译一下,就会生成一个以“.a”为后缀的静态库了
2.实现主界面
拉个按钮到界面上去,给它添加事件
主要代码就下面两行,完成了NSString 与 char* 的相互转化,并调用了接口

  1.     char* strWeatherInfo = getWeather([txtLocation.text UTF8String]);<br>    NSString *weatherInfo = [NSString stringWithUTF8String:strWeatherInfo];<br>
复制代码
最后将数据显示到界面上即可
五、Symbian平台
我始终对这个平台没啥好感,况且这个平台的开发本身就是使用C、C++,实现代码共用很容易的,在此我就不浪费笔墨了,有兴趣的自己试试。


六、总结
这一技术还是很有使用前景的,比如游戏开发者,可用通过代码共用,用Open GL 实现一个底层的游戏引擎给各个平台使用。
由于时间的关系,代码中对于异常的处理和一些条件的判断都没有去做,有兴趣的同学自己完善!
文章中的Demo已经打包,需要的可以自行下载。
下载地址:http://u.115.com/file/dn69hko2
在我的独立博客还有一些好文章,有兴趣的可以去看看:http://luzj.me/share-lib-test-mobil.html

作者:Luzj (luzjcn[at]gmail.com)
出处:http://luzj.me/share-lib-test-mobil.html
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册