`
seara
  • 浏览: 648551 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

流媒体程序开发之:H264解码器移植到OPhone

阅读更多
1. 移植目标
将H.264解码器移植到OPhone操作系统之上(NDK+C),并写一个测试程序(OPhoneSDK+Java)测试解码库是否正常运行,下面是解码时的截图:


OPhone的模拟器和Mobile的模拟器一样是模拟ARM指令的,不像Symbian模拟器一样执行的是本地代码,所以在模拟器上模拟出来的效率会比 真实手机上的效率要低,之前这款解码器已经优化到在nokia 6600(相当低端的一款手机,CPU主频才120Hz)上做到在线播放。

2. 面向人群
本文面向有一定的手机应用开发经验(例如:S60/Mobile/MTK)和有一定的跨手机平台移植经验的人员,帮助她们了解一个企业的核心库(C/C++)是怎么移植到OPhone之上的。

3. 假定前提
1)熟悉Java/C/C++语言;
2)熟悉Java的JNI技术;
3)有一定的跨手机平台移植经验;
4)有一套可供移植的源代码库,这里以H.264解码库为例,为了保护我们的知识版权,这里只能够公开头文件:

  1. #ifndef__H264DECODE_H__
  2. #define__H264DECODE_H__
  3. #ifdefined(__SYMBIAN32__)//S602rd/3rd/UIQ
  4. #include<e32base.h>
  5. #include<libc"stdio.h>
  6. #include<libc"stdlib.h>
  7. #include<libc"string.h>
  8. #else//Windows/Mobile/MTK/OPhone
  9. #include<stdio.h>
  10. #include<stdlib.h>
  11. #include<string.h>
  12. #endif
  13. classH264Decode
  14. {
  15. public:
  16. /***************************************************************************/
  17. /*构造解码器*/
  18. /*@returnH264Decode解码器实例*/
  19. /***************************************************************************/
  20. staticH264Decode*H264DecodeConstruct();
  21. /***************************************************************************/
  22. /*解码一帧*/
  23. /*@pInBuffer指向H264的视频流*/
  24. /*@iInSizeH264视频流的大小*/
  25. /*@pOutBuffer解码后的视频视频*/
  26. /*@iOutSize解码后的视频大小*/
  27. /*@return已解码的H264视频流的尺寸*/
  28. /***************************************************************************/
  29. intDecodeOneFrame(unsignedchar*pInBuffer,unsignedintiInSize,unsignedchar*pOutBuffer,unsignedint&iOutSize);
  30. ~H264Decode();
  31. };
  32. #endif//__H264DECODE_H__

你不用熟悉OPhone平台,一切从零开始,因为在此之前,我也不熟悉。

4. 开发环境(请参考: http://www.ophonesdn.com/documentation/)

5. 移植过程

5.1移植流程

5.2 封装Java接口

在“假定前提”中提到了要移植的函数,接下来会编写这些 函数的Java Native Interface。

  1. packageophone.streaming.video.h264;
  2. importjava.nio.ByteBuffer;
  3. publicclassH264decode{
  4. //H264解码库指针,因为Java没有指针一说,所以这里用一个32位的数来存放指针的值
  5. privatelongH264decode=0;
  6. static{
  7. System.loadLibrary("H264Decode");
  8. }
  9. publicH264decode(){
  10. this.H264decode=Initialize();
  11. }
  12. publicvoidCleanup(){
  13. Destroy(H264decode);
  14. }
  15. publicintDecodeOneFrame(ByteBufferpInBuffer,ByteBufferpOutBuffer){
  16. returnDecodeOneFrame(H264decode,pInBuffer,pOutBuffer);
  17. }
  18. privatenativestaticintDecodeOneFrame(longH264decode,ByteBufferpInBuffer,ByteBufferpOutBuffer);
  19. privatenativestaticlongInitialize();
  20. privatenativestaticvoidDestroy(longH264decode);
  21. }


这块没什么好说的,就是按照H264解码库的函数,封装的一层接口,如果你熟悉Java JNI,会发现原来是这么类似。这里插入一句:我一直认为技术都是相通的,底层的技术就那么几种,学懂了,其它技术都是一通百通。

5.3 使用C实现本地方法

5.3.1生成头文件

使用javah命令生成JNI头文件,这里需要注意是class路径不是源代码的路径,并且要加上包名:

这里生成了一个ophone_streaming_video_h264_H264decode.h,我们打开来看看:

  1. #include<jni.h>
  2. #ifndef_Included_ophone_streaming_video_h264_H264decode
  3. #define_Included_ophone_streaming_video_h264_H264decode
  4. #ifdef__cplusplus
  5. extern"C"{
  6. #endif
  7. JNIEXPORTjintJNICALLJava_ophone_streaming_video_h264_H264decode_DecodeOneFrame
  8. (JNIEnv*,jclass,jlong,jobject,jobject);
  9. JNIEXPORTjlongJNICALLJava_ophone_streaming_video_h264_H264decode_Initialize
  10. (JNIEnv*,jclass);
  11. JNIEXPORTvoidJNICALLJava_ophone_streaming_video_h264_H264decode_Destroy
  12. (JNIEnv*,jclass,jlong);
  13. #ifdef__cplusplus
  14. }
  15. #endif
  16. #endif

5.3.2实现本地方法

之前已经生成了JNI头文件,接下来只需要实现这个头文件的几个导出函数,这里以H264解码器的实现为例:

  1. #include"ophone_streaming_video_h264_H264decode.h"
  2. #include"H264Decode.h"
  3. JNIEXPORTjintJNICALLJava_ophone_streaming_video_h264_H264decode_DecodeOneFrame
  4. (JNIEnv*env,jclassobj,jlongdecode,jobjectpInBuffer,jobjectpOutBuffer){
  5. H264Decode*pDecode=(H264Decode*)decode;
  6. unsignedchar*In=NULL;unsignedchar*Out=NULL;
  7. unsignedintInPosition=0;unsignedintInRemaining=0;unsignedintInSize=0;
  8. unsignedintOutSize=0;
  9. jintDecodeSize=-1;
  10. jbyte*InJbyte=0;
  11. jbyte*OutJbyte=0;
  12. jbyteArrayInByteArrary=0;
  13. jbyteArrayOutByteArrary=0;
  14. //获取Input/OutByteBuffer相关属性
  15. {
  16. //Input
  17. {
  18. jclassByteBufferClass=env->GetObjectClass(pInBuffer);
  19. jmethodIDPositionMethodId=env->GetMethodID(ByteBufferClass,"position","()I");
  20. jmethodIDRemainingMethodId=env->GetMethodID(ByteBufferClass,"remaining","()I");
  21. jmethodIDArraryMethodId=env->GetMethodID(ByteBufferClass,"array","()[B");
  22. InPosition=env->CallIntMethod(pInBuffer,PositionMethodId);
  23. InRemaining=env->CallIntMethod(pInBuffer,RemainingMethodId);
  24. InSize=InPosition+InRemaining;
  25. InByteArrary=(jbyteArray)env->CallObjectMethod(pInBuffer,ArraryMethodId);
  26. InJbyte=env->GetByteArrayElements(InByteArrary,0);
  27. In=(unsignedchar*)InJbyte+InPosition;
  28. }
  29. //Output
  30. {
  31. jclassByteBufferClass=env->GetObjectClass(pOutBuffer);
  32. jmethodIDArraryMethodId=env->GetMethodID(ByteBufferClass,"array","()[B");
  33. jmethodIDClearMethodId=env->GetMethodID(ByteBufferClass,"clear","()Ljava/nio/Buffer;");
  34. //清理输出缓存区
  35. env->CallObjectMethod(pOutBuffer,ClearMethodId);
  36. OutByteArrary=(jbyteArray)env->CallObjectMethod(pOutBuffer,ArraryMethodId);
  37. OutJbyte=env->GetByteArrayElements(OutByteArrary,0);
  38. Out=(unsignedchar*)OutJbyte;
  39. }
  40. }
  41. //解码
  42. DecodeSize=pDecode->DecodeOneFrame(In,InRemaining,Out,OutSize);
  43. //设置Input/OutputByteBuffer相关属性
  44. {
  45. //Input
  46. {
  47. jclassByteBufferClass=env->GetObjectClass(pInBuffer);
  48. jmethodIDSetPositionMethodId=env->GetMethodID(ByteBufferClass,"position","(I)Ljava/nio/Buffer;");
  49. //设置输入缓冲区偏移
  50. env->CallObjectMethod(pInBuffer,SetPositionMethodId,InPosition+DecodeSize);
  51. }
  52. //Output
  53. {
  54. jclassByteBufferClass=env->GetObjectClass(pOutBuffer);
  55. jmethodIDSetPositionMethodId=env->GetMethodID(ByteBufferClass,"position","(I)Ljava/nio/Buffer;");
  56. //设置输出缓冲区偏移
  57. env->CallObjectMethod(pOutBuffer,SetPositionMethodId,OutSize);
  58. }
  59. }
  60. //清理
  61. env->ReleaseByteArrayElements(InByteArrary,InJbyte,0);
  62. env->ReleaseByteArrayElements(OutByteArrary,OutJbyte,0);
  63. returnDecodeSize;
  64. }
  65. JNIEXPORTjlongJNICALLJava_ophone_streaming_video_h264_H264decode_Initialize
  66. (JNIEnv*env,jclassobj){
  67. H264Decode*pDecode=H264Decode::H264DecodeConstruct();
  68. return(jlong)pDecode;
  69. }
  70. JNIEXPORTvoidJNICALLJava_ophone_streaming_video_h264_H264decode_Destroy
  71. (JNIEnv*env,jclassobj,jlongdecode){
  72. H264Decode*pDecode=(H264Decode*)decode;
  73. if(pDecode)
  74. {
  75. deletepDecode;
  76. pDecode=NULL;
  77. }
  78. }

5.3.3编译本地方法

接下来,只需要把用C实现的本地方法编译为动态链接库,如果之前你用于移植的那个库曾经移植到Symbian上过,那么编译会相当简单,因为NDK的编译器和Symbian的编译器一样,都是采用GCC做交叉编译器。

首先,需要在$NDK"apps目录下,创建一个项目目录,这里创建了一个H264Decode目录,在H264Decode目录中,创建一个Android.mk文件:

  1. APP_PROJECT_PATH:=$(callmy-dir)
  2. APP_MODULES:=H264Decode


接下来,需要在$NDK"source目录下,创建源代码目录(这里的目录名要和上面创建的项目目录文件名相同),这里创建一个H264Decode目录,然后把之前生成的JNI头文件和你实现的本地方法相关头文件和源代码,都拷贝到 这个目录下面。

然后,我们编辑Android.mk文件:

  1. LOCAL_PATH:=$(callmy-dir)
  2. include$(CLEAR_VARS)
  3. LOCAL_MODULE:=H264Decode
  4. LOCAL_SRC_FILES:=common.ccabac.cutils.cgolomb.cmpegvideo.cmem.cimgconvert.ch264decode.cpph264.cdsputil.cophone_streaming_video_h264_H264decode.cpp
  5. include$(BUILD_SHARED_LIBRARY)


关于Android.mk文件中,各个字段的解释,可以参考$NDK"doc下的《OPHONE-MK.TXT》和《OVERVIEW.TXT》,里面有详细的介绍。

最后,我们启动Cygwin,开始编译:

如果你看到了Install:**,这说明你的库已经编译好了。

FAQ 2:
如果编译遇到下面错误,怎么办?

  1. error:redefinitionoftypedef'int8_t'

需要注释掉你的代码中“typedef signed char int8_t;”,如果你的代码之前是已经移植到了Mobile/Symbian上的话,很有可能遇到这个问题。

5.4编写库测试程序

用Eclipse创建一个OPhone工程,在入口类中输入如下代码:

  1. /**
  2. *@authorophone
  3. *@email3751624@qq.com
  4. */
  5. packageophone.streaming.video.h264;
  6. importjava.io.File;
  7. importjava.io.FileInputStream;
  8. importjava.io.InputStream;
  9. importjava.nio.ByteBuffer;
  10. importOPhone.app.Activity;
  11. importOPhone.graphics.BitmapFactory;
  12. importOPhone.os.Bundle;
  13. importOPhone.os.Handler;
  14. importOPhone.os.Message;
  15. importOPhone.widget.ImageView;
  16. importOPhone.widget.TextView;
  17. publicclassH264ExampleextendsActivity{
  18. privatestaticfinalintVideoWidth=352;
  19. privatestaticfinalintVideoHeight=288;
  20. privateImageViewImageLayout=null;
  21. privateTextViewFPSLayout=null;
  22. privateH264decodeDecode=null;
  23. privateHandlerH=null;
  24. privatebyte[]Buffer=null;
  25. privateintDecodeCount=0;
  26. privatelongStartTime=0;
  27. publicvoidonCreate(BundlesavedInstanceState){
  28. super.onCreate(savedInstanceState);
  29. setContentView(R.layout.main);
  30. ImageLayout=(ImageView)findViewById(R.id.ImageView);
  31. FPSLayout=(TextView)findViewById(R.id.TextView);
  32. Decode=newH264decode();
  33. StartTime=System.currentTimeMillis();
  34. newThread(newRunnable(){
  35. publicvoidrun(){
  36. StartDecode();
  37. }
  38. }).start();
  39. H=newHandler(){
  40. publicvoidhandleMessage(Messagemsg){
  41. ImageLayout.invalidate();
  42. ImageLayout.setImageBitmap(BitmapFactory.decodeByteArray(Buffer,0,Buffer.length));
  43. longTime=(System.currentTimeMillis()-StartTime)/1000;
  44. if(Time>0){
  45. FPSLayout.setText("花费时间:"+Time+"秒解码帧数:"+DecodeCount+"FPS:"+(DecodeCount/Time));
  46. }
  47. }
  48. };
  49. }
  50. privatevoidStartDecode(){
  51. Fileh264file=newFile("/tmp/Demo.264");
  52. InputStreamh264stream=null;
  53. try{
  54. h264stream=newFileInputStream(h264file);
  55. ByteBufferpInBuffer=ByteBuffer.allocate(51200);//分配50k的缓存
  56. ByteBufferpRGBBuffer=ByteBuffer.allocate(VideoWidth*VideoHeight*3);
  57. while(h264stream.read(pInBuffer.array(),pInBuffer.position(),pInBuffer.remaining())>=0){
  58. pInBuffer.position(0);
  59. do{
  60. intDecodeLength=Decode.DecodeOneFrame(pInBuffer,pRGBBuffer);
  61. //如果解码成功,把解码出来的图片显示出来
  62. if(DecodeLength>0&&pRGBBuffer.position()>0){
  63. //转换RGB字节为BMP
  64. BMPImagebmp=newBMPImage(pRGBBuffer.array(),VideoWidth,VideoHeight);
  65. Buffer=bmp.getByte();
  66. H.sendMessage(H.obtainMessage());
  67. Thread.sleep(1);
  68. DecodeCount++;
  69. }
  70. }while(pInBuffer.remaining()>10240);//确保缓存区里面的数据始终大于10k
  71. //清理已解码缓冲区
  72. intRemaining=pInBuffer.remaining();
  73. System.arraycopy(pInBuffer.array(),pInBuffer.position(),pInBuffer.array(),0,Remaining);
  74. pInBuffer.position(Remaining);
  75. }
  76. }catch(Exceptione1){
  77. e1.printStackTrace();
  78. }finally{
  79. try{h264stream.close();}catch(Exceptione){}
  80. }
  81. }
  82. protectedvoidonDestroy(){
  83. super.onDestroy();
  84. Decode.Cleanup();
  85. }
  86. }

BMPImage是一个工具类,主要用于把RGB序列,转换为BMP图象用于显示:

  1. @authorophone
  2. *@email3751624@qq.com
  3. */
  4. packageophone.streaming.video.h264;
  5. importjava.nio.ByteBuffer;
  6. publicclassBMPImage{
  7. //---私有常量
  8. privatefinalstaticintBITMAPFILEHEADER_SIZE=14;
  9. privatefinalstaticintBITMAPINFOHEADER_SIZE=40;
  10. //---位图文件标头
  11. privatebytebfType[]={'B','M'};
  12. privateintbfSize=0;
  13. privateintbfReserved1=0;
  14. privateintbfReserved2=0;
  15. privateintbfOffBits=BITMAPFILEHEADER_SIZE+BITMAPINFOHEADER_SIZE;
  16. //---位图信息标头
  17. privateintbiSize=BITMAPINFOHEADER_SIZE;
  18. privateintbiWidth=176;
  19. privateintbiHeight=144;
  20. privateintbiPlanes=1;
  21. privateintbiBitCount=24;
  22. privateintbiCompression=0;
  23. privateintbiSizeImage=biWidth*biHeight*3;
  24. privateintbiXPelsPerMeter=0x0;
  25. privateintbiYPelsPerMeter=0x0;
  26. privateintbiClrUsed=0;
  27. privateintbiClrImportant=0;
  28. ByteBufferbmpBuffer=null;
  29. publicBMPImage(byte[]Data,intWidth,intHeight){
  30. biWidth=Width;
  31. biHeight=Height;
  32. biSizeImage=biWidth*biHeight*3;
  33. bfSize=BITMAPFILEHEADER_SIZE+BITMAPINFOHEADER_SIZE+biWidth*biHeight*3;
  34. bmpBuffer=ByteBuffer.allocate(BITMAPFILEHEADER_SIZE+BITMAPINFOHEADER_SIZE+biWidth*biHeight*3);
  35. writeBitmapFileHeader();
  36. writeBitmapInfoHeader();
  37. bmpBuffer.put(Data);
  38. }
  39. publicbyte[]getByte(){
  40. returnbmpBuffer.array();
  41. }
  42. privatebyte[]intToWord(intparValue){
  43. byteretValue[]=newbyte[2];
  44. retValue[0]=(byte)(parValue&0x00FF);
  45. retValue[1]=(byte)((parValue>>8)&0x00FF);
  46. return(retValue);
  47. }
  48. privatebyte[]intToDWord(intparValue){
  49. byteretValue[]=newbyte[4];
  50. retValue[0]=(byte)(parValue&0x00FF);
  51. retValue[1]=(byte)((parValue>>8)&0x000000FF);
  52. retValue[2]=(byte)((parValue>>16)&0x000000FF);
  53. retValue[3]=(byte)((parValue>>24)&0x000000FF);
  54. return(retValue);
  55. }
  56. privatevoidwriteBitmapFileHeader(){
  57. bmpBuffer.put(bfType);
  58. bmpBuffer.put(intToDWord(bfSize));
  59. bmpBuffer.put(intToWord(bfReserved1));
  60. bmpBuffer.put(intToWord(bfReserved2));
  61. bmpBuffer.put(intToDWord(bfOffBits));
  62. }
  63. privatevoidwriteBitmapInfoHeader(){
  64. bmpBuffer.put(intToDWord(biSize));
  65. bmpBuffer.put(intToDWord(biWidth));
  66. bmpBuffer.put(intToDWord(biHeight));
  67. bmpBuffer.put(intToWord(biPlanes));
  68. bmpBuffer.put(intToWord(biBitCount));
  69. bmpBuffer.put(intToDWord(biCompression));
  70. bmpBuffer.put(intToDWord(biSizeImage));
  71. bmpBuffer.put(intToDWord(biXPelsPerMeter));
  72. bmpBuffer.put(intToDWord(biYPelsPerMeter));
  73. bmpBuffer.put(intToDWord(biClrUsed));
  74. bmpBuffer.put(intToDWord(biClrImportant));
  75. }
  76. }


测试程序完整工程在此暂不提供。

5.5集成测试

集成测试有两点需要注意,在运行程序前,需要把动态库复制到模拟器的/system/lib目录下面,还需要把需要解码的视频传到模拟器的/tmp目录下。
这里要明确的是,OPhone和Symbian的模拟器都做的太不人性化了,Symbian复制一个文件到模拟器中,要进一堆很深的目录,OPhone的 更恼火,需要敲命令把文件传递到模拟器里,说实话,仅在这点上,Mobile的模拟器做的还是非常人性化的。
命令:

  1. PATH=D:"OPhone"OPhoneSDK"tools"
  2. adb.exeremount
  3. adb.exepushD:"Eclipse"workspace"H264Example"libs"armeabi"libH264Decode.so/system/lib
  4. adb.exepushD:"Eclipse"workspace"H264Example"Demo.264/tmp
  5. pause


这里解释一下abd push命令:
adb push <本地文件路径> <远程文件路径> - 复制文件或者目录到模拟器
在Eclipse中,启动库测试程序,得到画面如下:

FAQ 3:

模拟器黑屏怎么办?
这可能是由于模拟器启动速度比较慢所引起的,所以需要多等一会。希望下个版本能够改进。

原文地址:http://www.ophonesdn.com/article/show/45;jsessionid=306BD3BE92F43DC693BEB09B0234B036



国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

分享到:
评论

相关推荐

    OPhone UI开发 游戏编程 H264解码器移植到OPhone OPhone平台编写网络

    OPhone UI开发者指南 OPhone联网应用开发中的线程管理与界面更新 OPhone平台开发环境常见问题 OPhone游戏编程 流媒体程序开发之:H264解码器移植到OPhone 如何在OPhone平台编写网络应用

    OPhone平台多媒体应用程序开发介绍

    OPhone平台多媒体应用程序开发主要涉及Android系统的多媒体架构、多媒体驱动、OpenCore库、多媒体框架层以及关键的Java API。在Android系统中,多媒体组件自下而上包括多媒体驱动、多媒体Native库、多媒体框架层和...

    Android OPhone 开发完全讲义

    ### Android OPhone 开发完全讲义 #### 一、概览与目标读者 《Android OPhone 开发完全讲义》是一本集成了Android与OPhone两大移动操作系统开发知识的著作,由国内著名Android社区eoeandroid推荐。本书旨在为具备...

    Android/Ophone开发完全讲义

    《Android/Ophone开发完全讲义》是李宁老师编著的一本深入讲解Android与Ophone开发的书籍,全面覆盖了这两个平台的基础知识和技术要点。在本讲义中,作者旨在帮助开发者从零基础开始,逐步掌握Android和Ophone应用...

    j2me移植到Android(Ophone)-游戏文档

    手机游戏是目前深受广大手机用户喜爱的一种娱乐软件,各大运营商都有自己的手机游戏平台,比如中国移动的百宝箱,MM平台,当然...有了这个优点也就意味着所有的J2ME程序都可以非常快速的迁移到OPhone(Adnroid)平台。

    Ophone开发环境配置测试程序

    在本文中,我们将深入探讨如何配置Ophone开发环境并创建一个简单的Hello,OPhone应用程序,以便测试Ophone SDK的正确安装和使用。Ophone是一种基于Linux的智能手机操作系统,由中国移动开发,它支持Android应用程序...

    android ophone开发完全讲义源码ch18

    7. **多媒体支持**:OPhone可能对多媒体文件的处理有特别的需求,例如音频、视频的编码解码和流媒体播放。 8. **OPhone特定服务**:如位置服务、推送通知、运营商API等,这些都是OPhone独有的服务,开发者需要掌握...

    OMS OPhone Android 开发教程

    - **OPhone SDK 组成**:OPhone SDK 包含了用于开发应用程序的所有必要工具和资源,包括 API、模拟器、开发工具以及示例代码。 - **OPhone API**:提供了一系列特定于 OPhone 的功能,例如主屏幕管理、本地搜索、...

    OPhone应用开发权威指南

    本书系统地介绍了OPhone平台的体系结构、应用程序开发流程和调试技巧、OPhone应用程序开发中涉及的主要模块。全书结合30多个经典案例,阐述了OPhone平台的运行环境、应用程序模型、用户界面与图形引擎、数据持久化...

    Android/OPhone开发完全讲义 Android 完整代码

    这本书旨在帮助开发者全面掌握Android和OPhone平台的开发技能,从基础到高级,覆盖了整个移动应用开发的生命周期。 在Android开发部分,该讲义首先介绍了Android平台的基础知识,包括Android系统架构、开发环境搭建...

    Android/OPhone开发完全讲义 Android 完整开放源代码

    《Android/OPhone开发完全讲义》是一本深入探讨Android和OPhone开发的综合性教材,主要针对想要在Android平台上进行应用程序开发的工程师和技术爱好者。这本书不仅涵盖了Android的基础知识,还涉及了OPhone这一中国...

    《Android/OPhone开发完全讲义》(上)

    《Android/OPhone开发完全讲义》是李宁编著的一本专为Android和OPhone开发者准备的详尽教程,其上册主要涵盖了Android和OPhone平台的基础知识、开发环境搭建以及应用程序的基本构建过程。这份讲义对于初学者和有一定...

    OPhone开发环境搭建详解

    OPhone是中国移动主导的一款基于Android操作系统定制的开放式手机平台,它允许开发者利用Java或C++进行应用程序的开发。本文将深入探讨OPhone开发环境的搭建,帮助初学者快速上手,避免常见问题。 首先,我们需要...

    《Android-OPhone开发完全讲义》绝对完整源码

    《Android-OPhone开发完全讲义》是一本深入探讨Android应用程序开发的专业书籍,特别是针对OPhone平台的开发。OPhone是基于Android系统的一种定制版本,由中国移动推出,它在原生Android的基础上添加了一些特定的...

    AndroidOPhone开发完全讲义源码Android-OPhone-src

    《Android OPhone开发完全讲义源码Android-OPhone-src》是一份全面涵盖Android OPhone开发的源码解析资料,包含多个章节的源代码实例,旨在帮助开发者深入了解Android OPhone平台的内部工作原理和开发技术。...

    Android/Ophone开发完全讲义.rar

    《Android/Ophone开发完全讲义》是一份深入探讨Android与Ophone平台开发的综合性学习资料,其中包含了丰富的源码示例,旨在帮助开发者全面掌握这两种操作系统上的应用开发技能。源码是学习编程语言和理解软件架构的...

    安装OPhone SDK详细过程

    OPhone SDK,全称为Open Mobile Phone SDK,是基于Android SDK的扩展,主要用于开发针对OPhone操作系统的应用程序。OPhone是中国移动推出的一个基于Linux的智能手机操作系统,它融合了Android开放源码项目的优势,为...

    Ophone应用开发权威指南 光盘源码

    《Ophone应用开发权威指南》是一本专注于Ophone平台应用程序开发的专业书籍,其附带的光盘源码为读者提供了丰富的实践素材。Ophone是中国移动基于Android操作系统进行深度定制的一个智能手机平台,它在保留Android...

Global site tag (gtag.js) - Google Analytics