市场上有哪些androidapp是明显的使用了android ndk开发实例或者framework开发?...

NDK开发 - 简书
下载简书移动应用
写了161385字,被51人关注,获得了69个喜欢
一、NDK产生的背景Android平台从诞生起,就已经支持C、C++开发。众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第三方应用都必须使用Java语言。但这并不等同于“第三方应用只能使用Java”。在Android SDK首次发布时,Google就宣称其虚拟机Dalvik支持JNI编程方式,也就是第三方应用完全可以通过JNI调用自己的C动态库,即在Android平台上,“Java+C”的编程方式是一直都可以实现的。不过,Google也表示,使用原生SDK编程相比Dalvik虚拟机也有一些劣势,Android SDK文档里,找不到任何JNI方面的帮助。即使第三方应用开发者使用JNI完成了自己的C动态链接库(so)开发,但是so如何和应用程序一起打包成apk并发布?这里面也存在技术障碍。比如程序更加复杂,兼容性难以保障,无法访问Framework API,Debug难度更大等。开发者需要自行斟酌使用。于是NDK就应运而生了。NDK全称是Native Development Kit。NDK的发布,使“Java+C”的开发方式终于转正,成为官方支持的开发方式。NDK将是Android平台支持C开发的开端。二、为什么使用NDK1.代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。2.可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的。3.提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。4.便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。三、NDK简介1.NDK是一系列工具的集合NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。2.NDK提供了一份稳定、功能有限的API头文件声明Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。四、NDK开发环境的搭建1.下载安装Android NDK地址:2.下载安装cygwin由于NDK编译代码时必须要用到make和gcc,所以你必须先搭建一个linux环境, cygwin是一个在windows平台上运行的unix模拟环境,它对于学习unix/linux操作环境,或者从unix到windows的应用程序移植,非常有用。通过它,你就可以在不安装linux的情况下使用NDK来编译C、C++代码了。下载地址:1)然后双击运行吧,运行后你将看到安装向导界面。2)点击下一步,此时让你选择安装方式:Install from Internet:直接从Internet上下载并立即安装(安装完成后,下载好的安装文件并不会被删除,而是仍然被保留,以便下次再安装)。Download Without Installing:只是将安装文件下载到本地,但暂时不安装。Install from Local Directory:不下载安装文件,直接从本地某个含有安装文件的目录进行安装。3)选择第一项,然后点击下一步。4)选择要安装的目录,注意,最好不要放到有中文和空格的目录里,似乎会造成安装出问题,其它选项不用变,之后点下一步:5)上一步是选择安装cygwin的目录,这个是选择你下载的安装包所在的目录,默认是你运行setup.exe的目录,直接点下一步就可以:6)此时你共有三种连接方式选择:Direct Connection:直接连接。Use IE5 Settings:使用IE的连接参数设置进行连接。Use HTTP/FTP Proxy:使用HTTP或FTP代理服务器进行连接(需要输入服务器地址、端口号)。用户可根据自己的网络连接的实情情况进行选择,一般正常情况下,均选择第一种,也就是直接连接方式。然后再点击“下一步”。7)这是选择要下载的站点,选择后点下一步。8)此时会下载加载安装包列表9)Search是可以输入你要下载的包的名称,能够快速筛选出你要下载的包。那四个单选按钮是选择下边树的样式,默认就行,不用动。View默认是Category,建议改成full显示全部包再查,省的一些包被隐藏掉。左下角那个复选框是是否隐藏过期包,默认打钩,不用管它就行,下边开始下载我们要安装的包吧,为了避免全部下载,这里列出了后面开发NDK用得着的包:autoconf2.1、automake1.10、binutils、gcc-core、gcc- g++、gcc4-core、gcc4-g++、gdb、pcre、pcre-devel、gawk、make共12个包10)然后开始选择安装这些包吧,点skip,把它变成数字版本格式,要确保Bin项变成叉号,而Src项是源码,这个就没必要选了。11)下面测试一下cygwin是不是已经安装好了。运行cygwin,在弹出的命令行窗口输入:cygcheck -c cygwin命令,会打印出当前cygwin的版本和运行状 态,如果status是ok的话,则cygwin运行正常。然后依次输入gcc –version,g++ --version,make –version,gdb –version进行测试,如果都打印出版本信息和一些描述信息,则cygwin安装成功!3.配置 NDK 环境变量a.首先找到 cygwin 的安装目录,找到一个 home\& 你的用户名 &\.bash_profile 文件,我的是:E:\cygwin\home\Administrator\.bash_profile , ( 注意:我安装的时候我的 home 文件夹下面什么都没有,解决 的办法:首先打开环境变量,把里面的用户变量中的 HOME 变量删掉,在 E:\cygwin\home 文件夹下建立名为Administrator 的文件夹(是用户名),然后把 E:\cygwin\etc\skel\.bash_profile 拷贝到该文件夹下 ) 。b.打开 bash_profile 文件,添加 NDK=/cygdrive/& 你的盘符 &/ 例如:NDK=/cygdrive/e/android-ndk-r5export NDKNDK 这个名字是随便取的,为了方面以后使用方便,选个简短的名字,然后保存c.打开 cygwin ,输入 cd $NDK ,如果输出上面配置的 /cygdrive/e/android-ndk-r5 信息,则表明环境变量设置成功了。4.用 NDK 来编译程序a.现在我们用安装好的 NDK 来编译一个简单的程序吧,我们选择 ndk 自带的例子 hello-jni ,我的位于E:\android-ndk-r5\samples\hello-jni( 根据你具体的安装位置而定 ) ,b.运行 cygwin ,输入命令 cd /cygdrive/e/android-ndk-r5/samples/hello-jni ,进入到 E:\android-ndk-r5\samples\hello-jni 目录。c.输入 $NDK/ndk-build ,执行成功后,它会自动生成一个 libs 目录,把编译生成的 .so 文件放在里面。 ($NDK是调用我们之前配置好的环境变量, ndk-build 是调用 ndk 的编译程序 )d.此时去 hello-jni 的 libs 目录下看有没有生成的 .so 文件,如果有,你的 ndk 就运行正常啦!5.在 eclipse 中集成 c/c++ 开发环境a.装 Eclipse 的 C/C++ 环境插件: CDT ,这里选择在线安装。  首先登录 http://www.eclipse.org/cdt/downloads.php ,找到对应你 Eclipse 版本的 CDT 插件 的在线安装地址。b.然后点 Help 菜单,找到 Install New Software 菜单c.点击 Add 按钮,把取的地址填进去,出来插件列表后,选 Select All ,然后选择下一步即可完成安装。d.安装完成后,在 eclispe 中右击新建一个项目,如果出现了 c/c++ 项目,则表明你的 CDT 插件安装成功啦!6.配置 C/C++ 的编译器a.打开 eclipse ,导入ndk 自带的hello-jni 例子,右键单击项目名称,点击 Properties ,弹出配置界面,之后再点击 Builders ,弹出项目的编译工具列表,之后点击 New,新添加一个编译器,点击后出现添加界面,选择 Program ,点击 OK。b.出现了添加界面,首先给编译配置起个名字,如: C_Builder,设置 Location 为 & 你 cygwin 安装路径 &\bin\bash.exe 程序,例:E:\cygwin\bin\bash.exe ,设置Working Directory为&你 cygwin 安装路径 &\bin 目录,例如: E:\cygwin\bin,设置 Arguments 为 --login -c "cd /cygdrive/e/android-ndk-r5/samples/hello-jni && $NDK /ndk-build"上面的配置中 /cygdrive/e/android-ndk-r5/samples/hello-jni 是你当前要编译的程序的目录, $NDK 是之前配置
的 ndk 的环境变量,这两个根据你具体的安装目录进行配置,其他的不用变, Arguments 这串参数实际是
给 bash.exe 命令行程序传参数,进入要编译的程序目录,然后运行 ndk-build 编译程序c.接着切换到 Refresh 选项卡,给 Refresh resources upon completion 打上钩d.然后切换到 Build Options 选项卡,勾选上最后三项e.之后点击 Specify Resources 按钮,选择资源目录,勾选你的项目目录即可f.最后点击 Finish,点击 OK 一路把刚才的配置都保存下来,注意:如果你配置的编译器在其它编译器下边,记得一定要点 Up 按钮,把它排到第一位,否则 C 代码的编译晚于Java代码的编译,会造成你的 C 代码要编译两次才能看到最新的修改。g.编译配置也配置完成啦,现在来测试一下是否可以自动编译呢,打开项目 jni 目录里的 hello-jni.c 文件把提示 Hello from JNI! 改成其他的文字:如: Hello , My name is alex. ,然后再模 拟器中运行你的程序,如果模拟器中显示了你最新修改的文字,那么 Congratulations !你已经全部配置成功啦!五、开发自己的NDK程序入门的最好办法就是学习Android自带的例子, 这里就通过学习Android的NDK自带的demo程序:hello-jni来达到这个目的。1、 开发环境的搭建1)android的NDK开发需要在linux下进行: 因为需要把C/C++编写的代码生成能在arm上运行的.so文件,这就需要用到交叉编译环境,而交叉编译需要在linux系统下才能完成。2)安装android-ndk开发包,这个开发包可以在google android 官网下载: 通过这个开发包的工具才能将android jni 的C/C++的代码编译成库3)android应用程序开发环境: 包括eclipse、java、 android sdk、 adt等。如何下载和安装android-ndk我这里就不啰嗦了,安装完之后,需要将android-ndk的路劲加到环境变量PATH中:sudo gedit /etc/environment在environment的PATH环境变量中添加你的android-ndk的安装路劲,然后再让这个更改的环境变量立即生效:source
/etc/environment经过了上述步骤,在命令行下敲:ndk-bulid弹出如下的错误,而不是说ndk-build not found,就说明ndk环境已经安装成功了。Android NDK: Could not find application project directory !Android NDK: Please define the NDK_PROJECT_PATH variable to point to it./home/braincol/workspace/android/android-ndk-r5/build/core/build-local.mk:85: *** Android NDK: Aborting
Stop.2.代码的编写1)首先是写java代码建立一个Android应用工程HelloJni,创建HelloJni.java文件:HelloJni.java :importandroid.app.Aimportandroid.widget.TextVimportandroid.os.BpublicclassHelloJniextendsActivity{/**Called when the activity is first created.*/@OverridepublicvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);TextView
tv =newTextView(this);tv.setText( stringFromJNI() );setContentView(tv);}/*A native method that is implemented by the 'hello-jni' native library, which is packaged with this application.*/publicnativeString
stringFromJNI();publicnativeString
unimplementedStringFromJNI();/*this is used to load the 'hello-jni' library on application startup. The library has already been unpacked into/data/data/com.example.HelloJni/lib/libhello-jni.so at installation time by the package manager.*/static{System.loadLibrary("hello-jni");}}这段代码很简单,注释也很清晰,这里只提两点::static{System.loadLibrary("hello-jni");}表明程序开始运行的时候会加载hello-jni, static区声明的代码会先于onCreate方法执行。如果你的程序中有多个类,而且如果HelloJni这个类不是你应用程序的入口,那么hello-jni(完整的名字是libhello-jni.so)这个库会在第一次使用HelloJni这个类的时候加载。publicnative String stringFromJNI();publicnative String unimplementedStringFromJNI();可以看到这两个方法的声明中有 native 关键字, 这个关键字表示这两个方法是本地方法,也就是说这两个方法是通过本地代码(C/C++)实现的,在java代码中仅仅是声明。用eclipse编译该工程,生成相应的.class文件,这步必须在下一步之前完成,因为生成.h文件需要用到相应的.class文件。2)编写相应的C/C++代码刚开始学的时候,有个问题会让人很困惑,相应的C/C++代码如何编写,函数名如何定义? 这里讲一个方法,利用javah这个工具生成相应的.h文件,然后根据这个.h文件编写相应的C/C++代码。a. 生成相应.h文件:就拿我这的环境来说,首先在终端下进入刚刚建立的HelloJni工程的目录:braincol@ubuntu:~$ cd workspace/android/NDK/hello-jni/ls查看工程文件braincol@ubuntu:~/workspace/android/NDK/hello-jni$ lsAndroidManifest.xml
bindefault.properties
src可以看到目前仅仅有几个标准的android应用程序的文件(夹)。首先我们在工程目录下建立一个jni文件夹:braincol@ubuntu:~/workspace/android/NDK/hello-jni$ mkdir jnibraincol@ubuntu:~/workspace/android/NDK/hello-jni$ lsAndroidManifest.xml
bindefault.properties
src下面就可以生成相应的.h文件了:braincol@ubuntu:~/workspace/android/NDK/hello-jni$ javah -classpath bin -d jni com.example.hellojni.HelloJni-classpath bin:表示类的路劲-d jni: 表示生成的头文件存放的目录com.example.hellojni.HelloJni 则是完整类名这一步的成功要建立在已经在 bin/com/example/hellojni/
目录下生成了 HelloJni.class的基础之上。现在可以看到jni目录下多了个.h文件:braincol@ubuntu:~/workspace/android/NDK/hello-jni$ cd jni/braincol@ubuntu:~/workspace/android/NDK/hello-jni/jni$ lscom_example_hellojni_HelloJni.h我们来看看com_example_hellojni_HelloJni.h的内容:com_example_hellojni_HelloJni.h :/*DO NOT EDIT THIS FILE - it is machine generated*/#include /*Header for class com_example_hellojni_HelloJni*/#ifndef _Included_com_example_hellojni_HelloJni#define_Included_com_example_hellojni_HelloJni#ifdef __cplusplusextern"C"{#endif/** Class:
com_example_hellojni_HelloJni* Method:
stringFromJNI* Signature: ()Ljava/lang/S*/JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv *, jobject);/** Class:
com_example_hellojni_HelloJni* Method:
unimplementedStringFromJNI* Signature: ()Ljava/lang/S*/JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_unimplementedStringFromJNI(JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif上面代码中的JNIEXPORT 和 JNICALL 是jni的宏,在android的jni中不需要,当然写上去也不会有错。从上面的源码中可以看出这个函数名那是相当的长啊。。。。 不过还是很有规律的, 完全按照:java_pacakege_class_mathod 形式来命名。也就是说:Hello.java中 stringFromJNI() 方法对应于 C/C++中的 Java_com_example_hellojni_HelloJni_stringFromJNI() 方法HelloJni.java中的 unimplementedStringFromJNI() 方法对应于 C/C++中的 Java_com_example_hellojni_HelloJni_unimplementedStringFromJNI() 方法注意下其中的注释:Signature: ()Ljava/lang/S()Ljava/lang/S()表示函数的参数为空(这里为空是指除了JNIEnv *, jobject 这两个参数之外没有其他参数,JNIEnv*, jobject是所有jni函数必有的两个参数,分别表示jni环境和对应的java类(或对象)本身),Ljava/lang/S 表示函数的返回值是java的String对象。b. 编写相应的.c文件:hello-jni.c :#include #include /*This is a trivial JNI example where we use a native method* to return a new VM String. See the corresponding Java source* file located at:*
apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java*/jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ){return(*env)-&NewStringUTF(env,"Hello from JNI !");}这里只是实现了Java_com_example_hellojni_HelloJni_stringFromJNI方法,而 Java_com_example_hellojni_HelloJni_unimplementedStringFromJNI 方法并没有实现,因为在HelloJni.java中只调用了stringFromJNI()方法,所以unimplementedStringFromJNI()方法没有实现也没关系,不过建议最好还是把所有java中定义的本地方法都实现了,写个空函数也行啊。。。有总比没有好。Java_com_example_hellojni_HelloJni_stringFromJNI() 函数只是简单的返回了一个内容为 "Hello from JNI !" 的jstring对象(对应于java中的String对象)。hello-jni.c文件已经编写好了,现在可以把com_example_hellojni_HelloJni.h文件给删了,当然留着也行,只是我还是习惯把不需要的文件给清理干净了。3)编译hello-jni.c 生成相应的库a 编写Android.mk文件在jni目录下(即hello-jni.c 同级目录下)新建一个Android.mk文件,Android.mk 文件是Android 的 makefile文件,内容如下:# Copyright (C)2009The Android Open Source Project## Licensed under the Apache License, Version2.0(the"License");# you may not usethisfile exceptincompliance with the License.# You may obtain a copy of the License at##
http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed toinwriting, software# distributed under the Licenseisdistributed on an"AS IS"BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the Licenseforthe specific language governing permissions and# limitations under the License.#LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE
:= hello-jniLOCAL_SRC_FILES := hello-jni.cinclude $(BUILD_SHARED_LIBRARY)这个Androd.mk文件很短,下面我们来逐行解释下:LOCAL_PATH := $(call my-dir)一个Android.mk 文件首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。在这个例子中,宏函数’my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。include $( CLEAR_VARS)CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...), 除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。LOCAL_MODULE := hello-jni编译的目标对象,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。注意:编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'hello-jni'的共享库模块,将会生成'libhello-jni.so'文件。重要注意事项:如果你把库命名为‘libhello-jni’,编译系统将不会添加任何的lib前缀,也会生成 'libhello-jni.so',这是为了支持来源于Android平台的源代码的Android.mk文件,如果你确实需要这么做的话。LOCAL_SRC_FILES := hello-jni.cLOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。注意,默认的C++源码文件的扩展名是’.cpp’. 指定一个不同的扩展名也是可能的,只要定义LOCAL_DEFAULT_CPP_EXTENSION变量,不要忘记开始的小圆点(也就是’.cxx’,而不是’cxx’)include $(BUILD_SHARED_LIBRARY)BUILD_SHARED_LIBRARY表示编译生成共享库,是编译系统提供的变量,指向一个GNU Makefile脚本,负责收集自从上次调用'include $(CLEAR_VARS)'以来,定义在LOCAL_XXX变量中的所有信息,并且决定编译什么,如何正确地去做。还有 BUILD_STATIC_LIBRARY变量表示生成静态库:lib$(LOCAL_MODULE).a, BUILD_EXECUTABLE 表示生成可执行文件。b. 生成.so共享库文件Andro文件已经编写好了,现在可以用android NDK开发包中的 ndk-build脚本生成对应的.so共享库了,方法如下:braincol@ubuntu:~/workspace/android/NDK/hello-jni/jni$ cd ..braincol@ubuntu:~/workspace/android/NDK/hello-jni$ lsAndroidManifest.xml
default.properties
srcbraincol@ubuntu:~/workspace/android/NDK/hello-jni$ ndk-buildGdbserver
: [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserverGdbsetup
: libs/armeabi/gdb.setupInstall
: libhello-jni.so =& libs/armeabi/libhello-jni.so可以看到已经正确的生成了libhello-jni.so共享库了, 我们去 libs/armeabi/ 目录下看看:braincol@ubuntu:~/workspace/android/NDK/hello-jni$ cd libs/braincol@ubuntu:~/workspace/android/NDK/hello-jni/libs$ lsarmeabibraincol@ubuntu:~/workspace/android/NDK/hello-jni/libs$ cd armeabi/braincol@ubuntu:~/workspace/android/NDK/hello-jni/libs/armeabi$ lsgdbserver
libhello-jni.so4)在eclipse重新编译HelloJni工程,生成apkeclipse中刷新下HelloJni工程,重新编译生成apk,libhello-jni.so共享库会一起打包在apk文件内。在模拟器中看看运行结果。参考资料:http://blog.csdn.net/hhao137/article/details/4304664/hibraincol/archive//2063847.html/blog/946724/hibraincol/archive//2063847.html
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:扫一扫关注官方微信同时开发 Android 和 iOS apps 是一种什么样的体验?
按投票排序
申明:本人全职 Android 业余 iOS,只是不能苟同有人说的:"Android 基础设施对开发者更友好",并非刻意粉 iOS 黑 Android。最近项目中涉及图片/音视频处理,深有体会:至少在多媒体这块,iOS 的轮子明显更多、更好用。图像处理:iOS 的 CoreImage 库内置的 CIFilter 即可实现图片滤镜;Android 这边基本没有原生支持,只能依赖
等开源项目在 native 层实现,而且可能某些滤镜不支持 Alpha 通道,需要自己在 Java 层再次回炉处理恢复Alpha通道;另外 iOS 还有个强大的第三方库 ,基于 GPU 加速,不仅支持图片滤镜,还支持相机视频实时滤镜;Android 虽然也有人弄了个 ,但功能上与前者不可同日而语,实际项目中被运用的应该不多。流媒体播放:iOS 的 AVFoundation 库内置的 AVQueuePlayer 天然支持播放队列,实乃逆天神器啊;Android 的 VideoView 和 GLSurfaceView 一样继承自 SurfaceView,只支持绑定单个数据源,多个流媒体连续播放不太好无缝衔接(网上有人说可以通过 HttpProxy 实现预加载,这大概就是
所说的“奇技淫巧”);流媒体处理:iOS 的 AVFoundation 库内置的 AVMutableComposition / AVAssetExportSession / AVAssetReader / AVAssetWriter 等即可实现音视频合成;Android 这块的原生支持 MediaCodec / MediaMuxer / MediaExtrator / MediaSync 等直到 4.1 / 4.3 / 6.0 才引入,而且文档少;而
/ 等 Java 层开源项目也存在性能/格式支持等各种坑,最后只能老老实实滚回去研究
这个巨无霸了。最终结果:iOS 分分钟就能撸出原型 demo,而 Android 还在苦逼地各种技术调研。Android 轮子不给力,经常得自力更生。所以熟悉 C / C++、JNI / NDK 是必须的。PS:有人说我讲的太片面,14年写过一篇:。老文章了,如有纰漏请轻喷。PPS:同时写 Android 和 iOS 真的没啥。这年头不会几门外语都不好意思出门,我会告诉你14年一年我就学了七种语言么(Objective-C / Swift / Golang / Rust / Haskell / C++11 / Lua)?但熟悉 API 能写东西毕竟只是初级阶段,若想深入就得了解底层原理机制,而这是需要大量时间、精力、实践的。有种说法是要成为 T 型人才(注意不是 π 哦),首先你得有那一竖,然后追求那一横。踏踏实实打好基础(数据结构算法/操作系统/组成与体系结构/网络与密码/数据库,微积分/线性代数/离散数学/概率统计),并且在某一细分领域有所深入,然后再追求广度。合理构建完善的知识体系很重要,盲目地追求所谓的全栈是不可取的。之前在一个 Android 交流群看到有人说想学 iOS,理由是接外包更方便... 呵呵,真拿自己当 “码农” 啊。
哎,看不下去了一:开发环境iOS的Xcode是垃圾中的垃圾,尤其是现在对Swift的支持,我之前用的时候隔三差五的代码高亮崩溃了,Xcode的崩溃次数绝对是Android IDE的数倍起,而且真心卡,我感觉上下拖动都没60帧。Android以前的Eclipse也是垃圾,后来出的Intelijia/Android Studio好太多。代码多了也卡,所以我干脆直接指定给他3G内存用(我电脑是16G的13寸rmbp),会好很多。不过自从Android全面切到Gralde后,感觉Gradle编译真心慢,尤其是多module依赖的时候,还有方法数超过6k5需要multidex的时候简直是噩梦,因为开了multidex后是不支持增量编译。这方面iOS好很多,iOS用的多的是cocopod管理依赖,改几行代码编译速度确实比Gradle快。当然iOS可以用AppCode,但是这玩意老是跟不上Xcode的发版速度,比如iOS9出了,Xcode7出了,但是老得AppCode就没法写了,各种语法错误,得上新的开发版,但是开发版对于iOS新特性的支持肯定又不全二:开发语言iOS的OC语法怪异繁琐但是习惯就好,这玩意调用C/C++比Android用的Java好太多。后来的Swift改进太多,但是当前不成熟,主要是Xcode太垃圾,不过现在用Swift写的iOS App也渐渐多起来。Android的Java已死,死在1.7,是不可能上1.8的Lambda,虽然有第三方库搞这个。Jetbrain出的Kotlin对Android的支持也才开始,自己都没1.0,想用Kotlin写Android至少也得等个2,3年把。三:页面导航和保存现场iOS是用ViewController,Android用Activity,VC的push==Android的startActivity,VC的present==DialogFragment.show无论哪个系统都有内存不够的问题,在应用被切到后台,Android原生支持序列化保存现场,以便之后App被回收后再回来能恢复(当然你可以不做,比如某个版本的百度地图就是这么干的,每次切出去进来就重载),Fragment做的那么复杂也有这部分原因,iOS默认不支持,需要开发者自己写很繁琐的代码,所以你可以见到,基本上没有iOS应用在后台被销毁后重进还能恢复现场,一般都是重载页面复杂点的iOS App都要用到 ViewController互相内嵌,叫 ViewController Container,在Android上面就是Activity内嵌Fragment内嵌Child Fragment。VC之间传数据因为没有保存现场的需求,所以直接给VC对象的某个属性赋值就OK。Androd就得经过Intent,要求数据必须支持序列化,当然你要是不愿意保存现场,跟iOS差不多也行。其实我也不知道哪个算比较好,因为iOS也有人抱怨iOS的做法让2个VC耦合太强。四:App内存iOS App启动后有差不多1/2整个系统内存的可用大小,但是Android的差距就很大,从32mb到195mb+(2G总内存)都有,跟整个手机的总内存有关,没用过3G,4G内存的Android手机,不知道heap size是多少。这就导致Android的内存更容易出问题。反正都有代码没写好因为强引用导致内存泄露的问题五:UI,兼容性适配iOS从最早的手动Frame,为了适配ip4 ip5的auto resizing,后来的AutoLayout,后来的Size Class。但是StoryBoard的AutoLayout真的非常非常难用,稍微复杂点的界面,左侧一堆一堆的约束,根本不可能改的了的,对比起,容我现在先吐一下,我眼睛痛。所以很多人用第三方的代码AutoLayout库,比如Masonry,但是我用下来感觉还是啰嗦。iOS9为了搞适配,增加了UIStackView,这其实就是Android的LinearLayout。AutoLayout另外一个问题是卡,所以基本没人会在UITableView的Cell里面用AutoLayout,全是手动Frame布局的。iOS开发一直以来很多争吵,代码画布局(要么手动Frame,要么各种第三方布局库),还是全部StoryBoard/Xib,这2个都恶心,代码画,VC里面又是布局又是业务,后者又不是人能用的,StobyBoard/Xib的根本没有可读性可言,对于版本管理就是灾难。而且我个人对于Xcode能否打开复杂StoryBoard切保持不崩溃持有怀疑态度。Android通常是XML画布局,代码做业务,相对来说好太多,XML非常好读写,写个ListView的Cell的速度比UITableView快太多,iOS是需要你自己计算高度的,当然你可以不用,我上面也说了,你不怕卡的话。但是Android兼容麻烦的是Rom兼容,尤其是国内厂商,对于Framework层改动太多,很容易踩到坑。对于系统Api以及系统版本更新的坑,我印象里面,无论是iOS还是Android都不会少,逃不掉的,老老实实认命找workaround。六:多线程iOS的GCD NSOperation对Java的Executor多线程框架。就客户端开发而言,我没感觉出来这2者有什么麻烦或者为难的地方,都能满足需要,当然或许是我太浅薄。七:存储虽然iOS有CoreData,但是没人用啊,大家都喜欢SQLite,Androd官方是没ORM方案的,老老实实SQLite,第三方的ORM反正我心虚iOS分配给App的几个文件夹,如果你在不该写的文件夹写,比如一个会被iCloud备份的文件夹下当缓存用我记得是会被AppStore驳回的。但是Android随便了,整个SD卡可以读写,某个版本的Android是禁止写第二个存储空间的(多数都是SD卡),后来我记得又改回去了。八:动画iOS的RunLoop在Android那边就是Handler/Looper/MessageQueue。iOS的RunLoop多个模式,可以在滚动的时候禁止其他的UI消息,很像Android上就是MessageQueue.IdleHandler因为iOS要跟OS X共享代码,所以是拆分显示和事件处理(手机触摸屏,电脑就是鼠标键盘),也就有了CALayer和UIView,Android因为没历史包袱,都是View自己处理的。iOS动画可以直接操作CALayer做,Android一般是用Animator操作View,但是因为版本兼容性的问题,很多人还是会用2.x的Aniamtion来做Android动画,那东西渣多了。Animator的一个好处是可以任意属性对于时间的变化,Facebook给iOS出的Pop我记得也是可以这样,不然你就得自己用CADisplayLink封装了。动画过程中的快慢iOS上是TimingFunction负责,Android是Interpolator贝塞尔曲线 UIBezierPath 对应 PathViewController过场动画UIViewControllerTransitioning对应Android5的ActivityTransition,但是因为普遍Android手机版本跟不上。。。。很少有人用ActivityTransition。Androd没有iOS的UIKit Dynamics库,有些特效就得自己写九:上架我就以国内情况为例,你如果有个新App,上架AppStore需要一个月你得做好准备,Apple大爷是一周审核一次你的App,有一项通不过你再等一周吧,审核不过会给你截图和解释,你改吧,然后下周又有新问题,所以大约一个月,来来回去4次。国内没Google Play,所以你要么去小米商店,豌豆荚,应用宝,也得审核3,4天,比Apple要容易不少,但是渠道多,烦,一般还需要改Gradle脚本打包出不同渠道的包来判定对应的应用市场到底真的分发了多少来,都是跟钱有关。十:感觉写iOS是被Apple操,写Android是被各手机厂商操
目前在做一个需要ios和Android双平台移动端的产品,接触了一些HTML5的东西,觉得挺不错的,如果两个平台都有需求,预算又低,对界面没什么特殊要求,推荐HTML5。来个段子。美工给IOS出图,Android等了半天,也不见美工给自己出图,就去问美工,我这边咋没有图啊,美工看了一下Android,哦,你照着IOS的做就行了。
Android做UI适配方便,iOS做动画特效方便
就是ios很容易做的功能android的很多完全没法做。例如视频的剪辑合并特效,等等。
常常搞混%@和 %s,还有 {0} 数组List一类的常常要把.length, .size, .count 三个都打一遍才知道哪个对
一年Android,两年iOS来凑热闹。看到前辈们的各种吐槽,实在是不敢恭维,大概是加班太多了吧,但是我还是觉得,当你觉得一个东西太妈蛋难用的时候,是否有想过有自己的原因在里面?功夫无好坏,简单的招式练到极致,就是绝招……以下是我的观点:开发Android就像自己是主人,什么都要自己操一百个心。开发iOS就像自己是客人,衣食住行都有人争着帮你安排,但是你不能总是吃人家的吧?!
说 Android 系统和基础设施更友好,我简直是吓得目瞪口呆。Android,整个就是个奇技淫巧。你可以说 Android 比 iOS 能做的事情更多,但要说做一件事情更容易,这我是绝对不能认同的。写过三年 iOS,一年 Android。
两种模拟器一个天堂,一个地狱。
我想我这是最符合本意的回答,用rn,保存代码后,两个模拟器同时刷新界面很爽
已有帐号?
无法登录?
社交帐号登录

我要回帖

更多关于 android ndk 开发环境 的文章

 

随机推荐