Android之NDK开发

mikel阅读(753)

 一、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开发的开端。

 

二、为什么使用NDK

1.代码的保护。由于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

地址:http://developer.android.com/sdk/ndk/index.html

2.下载安装cygwin

由于NDK编译代码时必须要用到make和gcc,所以你必须先搭建一个linux环境, cygwin是一个在windows平台上运行的 unix模拟环境,它对于学习unix/linux操作环境,或者从unix到windows的应用程序移植,非常有用。通过它,你就可以在不安装 linux的情况下使用NDK来编译C、C++代码了。下载地址:http://www.cygwin.com

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/< 你的盘符 >/<android ndk 目录 > 例如:

NDK=/cygdrive/e/android-ndk-r5

export NDK

NDK 这个名字是随便取的,为了方面以后使用方便,选个简短的名字,然后保存

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 :

复制代码
import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;

public class HelloJni extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        TextView  tv = new TextView(this);
        tv.setText( stringFromJNI() );
        setContentView(tv);
    }


    /* A native method that is implemented by the 'hello-jni' native library, which is packaged with this application. */
    public native String  stringFromJNI();

    public native String  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这个类的时候加载。

public native String stringFromJNI();
public native 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$ ls
AndroidManifest.xml  assets  bin  default.properties  gen  res  src

可以看到目前仅仅有几个标准的android应用程序的文件(夹)。

首先我们在工程目录下建立一个jni文件夹:

braincol@ubuntu:~/workspace/android/NDK/hello-jni$ mkdir jni
braincol@ubuntu:~/workspace/android/NDK/hello-jni$ ls
AndroidManifest.xml  assets  bin  default.properties  gen  jni  res  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$ ls
com_example_hellojni_HelloJni.h

我们来看看com_example_hellojni_HelloJni.h的内容:

  com_example_hellojni_HelloJni.h :

复制代码
/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class com_example_hellojni_HelloJni */

#ifndef _Included_com_example_hellojni_HelloJni

#define _Included_com_example_hellojni_HelloJni

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:     com_example_hellojni_HelloJni

 * Method:    stringFromJNI

 * Signature: ()Ljava/lang/String;

 */

JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI

  (JNIEnv *, jobject);


/*

 * Class:     com_example_hellojni_HelloJni

 * Method:    unimplementedStringFromJNI

 * Signature: ()Ljava/lang/String;

 */

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/String;

()Ljava/lang/String;()表示函数的参数为空(这里为空是指除了JNIEnv *, jobject 这两个参数之外没有其他参数,JNIEnv*, jobject是所有jni函数必有的两个参数,分别表示jni环境和对应的java类(或对象)本身),Ljava/lang/String; 表示函数的返回值是java的String对象。

 

b. 编写相应的.c文件:

  hello-jni.c :

复制代码
#include <string.h>
#include <jni.h>


/* 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) 2009 The Android Open Source Project

#

# Licensed under the Apache License, Version 2.0 (the "License");

# you may not use this file except in compliance 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 to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS,

# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

# See the License for the specific language governing permissions and

# limitations under the License.

#

LOCAL_PATH := $(call my-dir)



include $(CLEAR_VARS)



LOCAL_MODULE    := hello-jni

LOCAL_SRC_FILES := hello-jni.c



include $(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.c

LOCAL_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$ ls
AndroidManifest.xml  assets  bin  default.properties  gen  jni  libs  obj  res  src
braincol@ubuntu:~/workspace/android/NDK/hello-jni$ ndk-build
Gdbserver      : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver
Gdbsetup       : libs/armeabi/gdb.setup
Install        : 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$ ls
armeabi
braincol@ubuntu:~/workspace/android/NDK/hello-jni/libs$ cd armeabi/
braincol@ubuntu:~/workspace/android/NDK/hello-jni/libs/armeabi$ ls
gdbserver  gdb.setup  libhello-jni.so

4)在eclipse重新编译HelloJni工程,生成apk

eclipse中刷新下HelloJni工程,重新编译生成apk,libhello-jni.so共享库会一起打包在apk文件内。在模拟器中看看运行结果。

 

参考资料:

http://blog.csdn.net/hhao137/article/details/4304664

http://www.cnblogs.com/hibraincol/archive/2011/05/30/2063847.html

http://yueguc.iteye.com/blog/946724

http://www.cnblogs.com/hibraincol/archive/2011/05/30/2063847.html

Qualcomm AR SDK之替换模型

mikel阅读(870)

1、将模型转换为.obj格式,这个通过很多三维软件都可以实现,我用的是3Dmax。

2、将obj文件转换为.h文件

因为高通ARsdk识别的是这类的头文件。头文件中包含了这个模型的坐标数据。提取这些坐标数据通过OpenGL进行渲染就可以绘制出图形。这是后话。现 在介绍怎么将obj文件转为头文件。首先从网上下载ActivePerl和obj2opengl.pl。ActivePerl是一个perl的脚本解释 器。obj2opengl.pl就是使用perl语言写的一个脚本程序。顾名思义,就可以知道这个脚本程序的作用就是将obj->opengl能够 使用的头文件。这两个可以在下面这个链接下载:

http://download.csdn.net/detail/ggtaas/4998573

http://download.csdn.net/detail/ggtaas/4998714

ActivePerl解压之后直接安装,一般安装在c盘的perl文件夹下,然后将第二个压缩包解压得到的obj2opengl.pl文件拷贝进bin文 件夹下。这样这个工具就可以用了。很简单吧。下面将你需要转换的obj文件也拷贝进bin文件夹中,例如是banana.obj,再运行下面的dos命令 就可以了,见下图:

这样你会发现你的bin文件夹下就多生成了一个banana.h文件。

3、替换模型,这里我们以ImageTargets为例,将生成的banana.h文件替换程序中的teapot.h。

首先来简单看一下生成的头文件的内容:

Plain Text code

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<span style="font-family:SimSun;font-size:14px;">/*                                                           
created with obj2opengl.pl                                   
                                                             
source file    : .\banana.obj                                
vertices       : 4032                                        
faces          : 8056                                        
normals        : 4032                                        
texture coords : 4420                                        
                                                             
                                                             
// include generated arrays                                  
#import ".\banana.h"                                         
                                                             
// set input data to arrays                                  
glVertexPointer(3, GL_FLOAT, 0, bananaVerts);                
glNormalPointer(GL_FLOAT, 0, bananaNormals);                 
glTexCoordPointer(2, GL_FLOAT, 0, bananaTexCoords);          
                                                             
// draw data                                                 
glDrawArrays(GL_TRIANGLES, 0, bananaNumVerts);               
*/                                                            
                                                              
unsigned int bananaNumVerts = 24168;                          
                                                              
float bananaVerts [] = {                                      
  // f 231/242/231 132/142/132 131/141/131                    
  0.172233487787643, -0.0717437751698985, 0.228589675538813,  
  0.176742968653347, -0.0680393472738536, 0.2284149434494,    
  0.167979223684599, -0.0670168837233226, 0.24286384937854,   
  // f 131/141/131 230/240/230 231/242/231                    
  0.167979223684599, -0.0670168837233226, 0.24286384937854,   
  0.166391290343292, -0.0686544011752973, 0.241920432968569,  
………………</span>  

由于篇幅有限制截取这么一点。其实已经够了,下面的都是类似这样的坐标值。那主要有哪些呢?看下面这些就可以了,在程序里面需要用到的就是这些。opengl的基础知识,这里就不赘述了。

Plain Text code

?

1
2
3
4
5
6
7
8
9
10
<span style="font-family:SimSun;font-size:14px;">// include generated arrays                                 
#import ".\banana.h"                                        
                                                            
// set input data to arrays                                 
glVertexPointer(3, GL_FLOAT, 0, <span style="color:#ff0000;">bananaVerts</span>);               
glNormalPointer(GL_FLOAT, 0, <span style="color:#ff0000;">bananaNormals</span>);                
glTexCoordPointer(2, GL_FLOAT, 0, bananaTexCoords);         
                                  <span style="color:#ff0000;">               </span>           
// draw data                                                
glDrawArrays(GL_TRIANGLES, 0, bananaNumVerts);</span>

切入正题:

准备工作:把banana.h拷贝到jni文件夹下。把banana.jpg拷贝到assets文件下。在ImageTargets文件夹打开Jni文件夹。打开ImageTargets.cpp

1.#include”Teapot.h” ->#include”banana.h”

2.

glTexCoordPointer(2, GL_FLOAT, 0, (const GLvoid*)&teapotTexCoords[0]);

glVertexPointer(3, GL_FLOAT, 0, (const GLvoid*) &teapotVertices[0]);

glNormalPointer(GL_FLOAT, 0, (const GLvoid*) &teapotNormals[0]);

glDrawElements(GL_TRIANGLES, NUM_TEAPOT_OBJECT_INDEX, GL_UNSIGNED_SHORT,

(const GLvoid*)&teapotIndices[0]);

改为:

glTexCoordPointer(2, GL_FLOAT, 0, (constGLvoid*) &bananaTexCoords[0]);

glVertexPointer(3, GL_FLOAT, 0, (const GLvoid*) & bananaVerts [0]);

glNormalPointer(GL_FLOAT, 0, (const GLvoid*) &bananaNormals[0]);

glDrawArrays(GL_TRIANGLES, 0, bananaNumVerts);

3.

glVertexAttribPointer(vertexHandle, 3, GL_FLOAT, GL_FALSE, 0, (constGLvoid*) &teapotVertices[0]);

glVertexAttribPointer(normalHandle, 3, GL_FLOAT, GL_FALSE, 0, (constGLvoid*) &teapotNormals[0]);

glVertexAttribPointer(textureCoordHandle, 2, GL_FLOAT, GL_FALSE, 0, (constGLvoid*) &teapotTexCoords[0]);

改为:

glVertexAttribPointer(vertexHandle,3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) &bananaVerts[0]);

glVertexAttribPointer(normalHandle,3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) &bananaNormals[0]);

glVertexAttribPointer(textureCoordHandle,2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) &bananaTexCoords[0]);

4.

glDrawElements(GL_TRIANGLES,NUM_TEAPOT_OBJECT_INDEX, GL_UNSIGNED_SHORT, (const GLvoid*)&teapotIndices[0]);

改为:

glDrawArrays(GL_TRIANGLES, 0,bananaNumVerts);

5. 设置 kObjectScale= 120.f;

为了使模型的大小适当,否则模型太小了。

6.打开src文件夹,com文件夹,qualcomm文件夹,打开ImageTargets.java。在 private void loadTextures()添 加: mTextures.add(Texture.loadTextureFromApk(“banana.jpg”,getAssets())); 如 下所示:

private voidloadTextures()

{

mTextures.add(Texture.loadTextureFromApk(“banana.jpg”,getAssets()));

//mTextures.add(Texture.loadTextureFromApk(“TextureTeapotBrass.png”, getAssets()));

//mTextures.add(Texture.loadTextureFromApk(“TextureTeapotBlue.png”, getAssets()));

//mTextures.add(Texture.loadTextureFromApk(“TextureTeapotRed.png”, getAssets()));

}

7.在cygwin一直cd到imagetargets目录后NDK-build可得结果。

最后效果图如下:


问题:现在换模型是可以实现了,但是有的模型包含多个贴图,本人能力有限,还贴不好。希望有兴趣的可以一起研究交流一下,也希望高手可以指导一下,~_~谢谢!本人QQ:472947433

如果大家觉得有什么问题或者建议的话也可以联系我!

[转载]移动应用(手机应用)开发IM聊天程序解决方案 - hoojo - 博客园

mikel阅读(665)

来源: [转载]移动应用(手机应用)开发IM聊天程序解决方案 – hoojo – 博客园

这个解决方法已经定制下来很久了,上一段时间比较忙,没有时间整这些东西。最近稍微好 些,不怎么加班。所以抽空总结下,同时也分享给大家,也算是给大家一个借鉴吧!或许这并不是最好的解决方案,但只要能满足当前需求的最好方案也算是最好的 解决方案,谁说不是呢!O(∩_∩)O~

 

我们采用的方案如下:

先看图

xmpp-server-client

上图的流程大致上是这样的:

手机端向PC端发送聊天内容

1、手机端程序通过Socket连接服务器端的ServerSocket

2、然后服务器端根据手机Mobile客户端发送过来统一规范的报文或聊天内容,进行解析

3、然后将解析的内容,再用smack框架转发到openfire服务器

4、最后由openfire服务器向客户端(BS、CS、PhoneClient)程序发送聊天信息。这里的客户端可以是pc上的浏览器,pc上的桌面应用,手机应用等

5、PC客户端BS程序(用http bind方式监听)的长连接监听到openfire服务器发送过来的数据,直接在页面中显示

 

同样,PC客户端向手机端发送聊天内容

1、PC客户端(BS)可以直接用http bind(xmpp 提供的http请求的长连接方式)直接向openfire服务器发送聊天数据;

2、然后openfire服务器接收到聊天内容的时候,这时候socket服务器中的smack框架中有一个聊天内容的监听器

3、监听到PC端向openfire发送的内容后,会用socket的流向手机端发送我们定义好的报文或是聊天内容

4、手机端的socket会不停的轮询(可以模拟心跳式长连接的方式),判断是否有消息到达,如果有则显示

 

而普通的聊天程序的流程则是客户端发送信息到openfire服务器,openfire服务器再将消息转发给其他客户端。他们省去了socket服务器这部分,那我们为什么要加上socket服务器这部分呢?

我们这样做也是有自己的道理的:

首先,如果让手机端自己实现向openfire服务器发送程序的代码,那工作量是相当大的。因为每个手机平台使用的语言都不同,每个平台都需要实现 向openfire服务器发送聊天信息的报文。这其实就是在做重复的工作,而且每个平台实现向手机端发送报文信息的技术会让每个手机端的开发人员都要学会 一套和openfire交互的代码。这势必会重复工作、重复相同业务的代码。所以,把这些代码放在一个tcp/ip的socket中转服务器进行统一发 送,这也是有好处的。

其次,把所以发送消息在报文在socket服务器完成,可以对业务进行一个统一的处理、消息过滤。

 

手机端被否决的解决方案,供参考

手机端用http长连接的方式,这个是不行的

其一、手机的移动网络不稳定,长连接会经常断掉,当然你可以自动进行重连

其二、长连接一直连接在服务器上,占用服务器资源。当然你可以使用心跳式长连接或是轮询方式

其三、手机端一直连接服务器会使用手机端用户的网络带宽流量(流量不是免费的,客户会怎么想)

其四、手机端一直连着服务器,对手机的电量也有消耗(现在智能机解决电量也是一个问题)

[转载]Openfire与XMPP协议 - hoojo - 博客园

mikel阅读(853)

来源: [转载]Openfire与XMPP协议 – hoojo – 博客园

关于xmpp协议可以参考:http://www.jabbercn.org

什么是OpenFire

Openfire 采用Java开发,开源的实时协作(RTC)服务器基于XMPP(Jabber)协议。

您可以使用它轻易的构建高效率的即时通信服务器。Openfire安装和使用都非常简单,并利用Web进行管理。单台服务器可支持上万并发用户。

由于是采用开放的XMPP协议,您可以使用各种支持XMPP协议的IM客户端软件登陆服务。

XMPPJabber)协议

1、 介绍

XMPP 是一种基于XML的协议,它继承了在XML环境中灵活的发展性。因此,基于XMPP的应用具有超强的可扩展性。经过扩展以后的XMPP可以通过发送扩展的 信息来处理用户的需求,以及在XMPP的顶端建立如内容发布系统和基于地址的服务等应用程 序。而且,XMPP包含了针对服务器端的软件协议,使之能与另一个进行通话,这使得开发者更容易建立客户应用程序或给一个配好系统添加功能。

2、 定义:

XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测。它在促进服务器之间的准即时操作。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息,即使其操作系统和浏览器不同。

XMPP的前身是Jabber, 一个开源形式组织产生的网络即时通信协议。XMPP目前被IETF国际标准组织完成了标准化工作。标准化的核心结果分为两部分;

核心的XML流传输协议

基于XML FreeEIM流传输的即时通讯扩展应用

XMPP的核心XML流传输协议的定义使得XMPP能够在一个比以往网络通信协议更规范的平台上。借助于XML易于解析和阅读的特性,使得XMPP的协议能够非常漂亮。

XMPP的即时通讯扩展应用部分是根据IETF在这之前对即时通讯的一个抽象定义的,与其他业已得到广泛使用的即时通讯协议,诸如AIM,QQ等有功能完整,完善等先进性。

在IETF 中,把IM协议划分为四种协议,即时信息和出席协议(Instant Messaging and Presence Protocol, IMPP)、出席和即时信息协议(Presence and Instant Messaging Protocol, PRIM)、针对即时信息和出席扩展的会话发起协议(Session Initiation Protocol for Instant Messaging and Presence Leveraging Extensions, SIMPLE),以及可扩展的消息出席协议(XMPP)。最初研发IMPP 也是为了创建一种标准化的协议,但是今天,IMPP 已经发展成为基本协议单元,定义所有即时通信协议应该支持的核心功能集。

3、 XMPP协议的优点

a. XMPP 协议是公开的,由JSF开源社区组织开发的。XMPP 协议并不属于任何的机构和个人,而是属于整个社区,这一点从根本上保证了其开放性。

b. XMPP 协议具有良好的扩展性。在XMPP 中,即时消息和到场信息都是基于XML 的结构化信息,这些信息以XML 节(XML Stanza)的形式在通信实体间交换。XMPP 发挥了XML 结构化数据的通用传输层的作用,它将出席和上下文敏感信息嵌入到XML 结构化数据中,从而使数据以极高的效率传送给最合适的资源。基于XML 建立起来的应用具有良好的语义完整性和扩展性。

c. 分布式的网络架构。XMPP 协议都是基于Client/Server 架构,但是XMPP协议本身并没有这样的限制。网络的架构和电子邮件十分相似,但没有结合任何特定的网络架构,适用范围非常广泛。

d. XMPP 具有很好的弹性。XMPP 除了可用在即时通信的应用程序,还能用在网络管理、内容供稿、协同工具、档案共享、游戏、远端系统监控等。

e. 安全性。XMPP在Client-to-Server通信,和Server-to-Server通信中都使用TLS (Transport Layer Security)协议作为通信通道的加密方法,保证通信的安全。任何XMPP服务器可以独立于公众XMPP网络(例如在企业内部网络中),而使用 SASL及TLS等技术更加增强了通信的安全性。如下图所示:

4、 XMPP协议的组成

主要的XMPP 协议范本及当今应用很广的XMPP 扩展:

l RFC 3920 XMPP(新的RFC6120):核心。定义了XMPP 协议框架下应用的网络架构,引入了XML Stream(XML 流)与XML Stanza(XML 节),并规定XMPP 协议在通信过程中使用的XML 标签。使用XML 标签从根本上说是协议开放性与扩展性的需要。此外,在通信的安全方面,把TLS 安全传输机制与SASL 认证机制引入到内核,与XMPP 进行无缝的连接,为协议的安全性、可靠性奠定了基础。Core 文档还规定了错误的定义及处理、XML 的使用规范、JID(Jabber Identifier,Jabber 标识符)的定义、命名规范等等。所以这是所有基于XMPP 协议的应用都必需支持的文档。

l RFC 3921:用户成功登陆到服务器之后,发布更新自己的在线好友管理、发送即时聊天消息等业务。所有的这些业务都是通过三种基本的XML 节来完成的:IQ Stanza(IQ 节), Presence Stanza(Presence 节), Message Stanza(Message 节)。RFC3921 还对阻塞策略进行了定义,定义是多种阻塞方式。可以说,RFC3921 是RFC3920 的充分补充。两个文档结合起来,就形成了一个基本的即时通信协议平台,在这个平台上可以开发出各种各样的应用。

l XEP-0030 服务搜索。一个强大的用来测定XMPP 网络中的其它实体所支持特性的协议。

l XEP-0115 实体性能。XEP-0030 的一个通过即时出席的定制,可以实时改变交变广告功能。

l XEP-0045 多人聊天。一组定义参与和管理多用户聊天室的协议,类似于Internet 的Relay Chat,具有很高的安全性。

l XEP-0096 文件传输。定义了从一个XMPP 实体到另一个的文件传输。

l XEP-0124 HTTP 绑定。将XMPP 绑定到HTTP 而不是TCP,主要用于不能够持久的维持与服务器TCP 连接的设备。

l XEP-0166 Jingle。规定了多媒体通信协商的整体架构。

l XEP-0167 Jingle Audio Content Description Format。定义了从一个XMPP 实体到另一个的语音传输过程。

l XEP-0176 Jingle ICE(Interactive Connectivity Establishment)Transport。ICE传输机制,文件解决了如何让防火墙或是NAT(Network Address Translation)保护下的实体建立连接的问题。

l XEP-0177 Jingle Raw UDP Transport。纯UDP 传输机制,文件讲述了如何在没有防火墙且在同一网络下建立连接的。

l XEP-0180 Jingle Video Content Description Format。定义了从一个XMPP 实体到另一个的视频传输过程。

l XEP-0181 Jingle DTMF(Dual Tone Multi-Frequency)。

l XEP-0183 Jingle Telepathy Transport Method。

5、 XMPP协议网络架构

XMPP 是一个典型的C/S架构,而不是像大多数即时通讯软件一样,使用P2P客户端到客户端的架构,也就是说在大多数情况下,当两个客户端进行通讯时,他们的消 息都是通过服务器传递的(也有例外,例如在两个客户端传输文件时).采用这种架构,主要是为了简化客户端,将大多数工作放在服务器端进行,这样,客户端的 工作就比较简单,而且,当增加功能时,多数是在服务器端进行.XMPP服务的框架结构如下图所示.XMPP中定义了三个角色,XMPP客户端,XMPP服 务器、网关.通信能够在这三者的任意两个之间双向发生.服务器同时承担了客户端信息记录、连接管理和信息的路由功能.网关承担着与异构即时通信系统的互联 互通,异构系统可以包括SMS(短信)、MSN、ICQ等.基本的网络形式是单客户端通过TCP/IP连接到单服务器,然后在之上传输XML,工作原理 是:

(1) 点连接到服务器;

(2) 务器利用本地目录系统中的证书对其认证;

(3) 点指定目标地址,让服务器告知目标状态;

(4) 务器查找、连接并进行相互认证;

(5) 点之间进行交互;

6、 XMPP客户端

XMPP 系统的一个设计标准是必须支持简单的客户端。事实上,XMPP 系统架构对客户端只有很少的几个限制。一个XMPP 客户端必须支持的功能有:

1. 通过 TCP 套接字与XMPP 服务器进行通信;

2. 解析组织好的 XML 信息包;

3. 理解消息数据类型。

XMPP 将复杂性从客户端转移到服务器端。这使得客户端编写变得非常容易,更新系统功能也同样变得容易。XMPP 客户端与服务端通过XML 在TCP 套接字的5222 端口进行通信,而不需要客户端之间直接进行通信。

基本的XMPP 客户端必须实现以下标准协议(XEP-0211):

RFC3920 核心协议Core

RFC3921 即时消息和出席协议Instant Messaging and Presence

XEP-0030 服务发现Service Discovery

XEP-0115 实体能力Entity Capabilities

7、 XMPP服务器

XMPP 服务器遵循两个主要法则:

1、监听客户端连接,并直接与客户端应用程序通信;

2、与其他 XMPP 服务器通信;

XMPP 开源服务器一般被设计成模块化,由各个不同的代码包构成,这些代码包分别处理Session管理、用户和服务器之间的通信、服务器之间的通信、 DNS(Domain Name System)转换、存储用户的个人信息和朋友名单、保留用户在下线时收到的信息、用户注册、用户的身份和权限认证、根据用户的要求过滤信息和系统记录 等。另外,服务器可以通过附加服务来进行扩展,如完整的安全策略,允许服务器组件的连接或客户端选择,通向其他消息系统的网关。

基本的XMPP 服务器必须实现以下标准协议

RFC3920 核心协议Core

RFC3921 即时消息和出席协议Instant Messaging and Presence

XEP-0030 服务发现Service Discovery

8、 XMPP网关

XMPP 突出的特点是可以和其他即时通信系统交换信息和用户在线状况。由于协议不同,XMPP 和其他系统交换信息必须通过协议的转换来实现,目前几种主流即时通信协议都没有公开,所以XMPP 服务器本身并没有实现和其他协议的转换,但它的架构允许转换的实现。实现这个特殊功能的服务端在XMPP 架构里叫做网关(gateway)。目前,XMPP 实现了和AIM、ICQ、IRC、MSN Massager、RSS0.9 和Yahoo Massager 的协议转换。由于网关的存在,XMPP 架构事实上兼容所有其他即时通信网络,这无疑大大提高了XMPP 的灵活性和可扩展性。

9、 XMPP地址格式

一个实体在XMPP网络结构中被称为一个接点,它有唯一的标示符jabber identifier(JID),即实体地址,用来表示一个Jabber用户,但是也可以表示其他内容,例如一个聊天室.一个有效的JID包括一系列元素:

(1) 名(domain identifier);

(2) 点(node identifier);

(3) 源(resource identifier).

它 的格式是node@domain/resource,node@domain,类似电子邮件的地址格式.domain用来表示接点不同的设备或位置,这个 是可选的,例如a在Server1上注册了一个用户,用户名为doom,那么a的JID就是doom@serverl,在发送消息时,指明 doom@serverl就可以了,resource可以不用指定,但a在登录到这个Server时,fl的JID可能是doom@serverl、 exodus(如果a用Exodus软件登录),也可能是doom@serverl/psi(如果a用psi软件登录).资源只用来识别属于用户的位置或 设备等,一个用户可以同时以多种资源与同一个XMPP服务器连接。

10、 XMPP消息格式

XMPP中定义了3个顶层XML元素: Message、Presence、IQ,下面针对这三种元素进行介绍。

<Message>

用于在两个jabber用户之间发送信息。Jsm(jabber会话管理器)负责满足所有的消息,不管目标用户的状态如何。如果用户在线jsm立即提交;否则jsm就存储。

To : 标识消息的接收方。

from : 指发送方的名字或标示(id)

Text: 此元素包含了要提交给目标用户的信息。

结构如下所示:

<message to= ‘lily@jabber.org/contact’ type =’chat’>

<body> 你好,在忙吗</body>

</message>

<Presence>

用来表明用户的状态,如:online、away、dnd(请勿打扰)等。当用户离线或改变自己的状态时,就会在stream的上下文中插入一个Presence元素,来表明自身的状态.结构如下所示:

<presence>

From =‘lily @ jabber.com/contact’

To = ‘yaoman @ jabber.com/contact’

<status> Online </status>

</presence>

<presence>元素可以取下面几种值:

Probe: 用于向接受消息方法发送特殊的请求

subscribe: 当接受方状态改变时,自动向发送方发送presence信息。

< IQ >

一种请求/响应机制,从一个实体从发送请求,另外一个实体接受请求,并进行响应.例如,client在stream的上下文中插入一个元素,向Server请求得到自己的好友列表,Server返回一个,里面是请求的结果.

<iq > 主要的属性是type。包括:

Get :获取当前域值。

Set :设置或替换get查询的值。

Result :说明成功的响应了先前的查询。

Error: 查询和响应中出现的错误。

结构如下所示:

<iq from =‘lily @ jabber.com/contact’id=’1364564666’ Type=’result’>

XMPP通信协议

一、 Stream

<!-- #################### 通信内容采用压缩技术,以及通信的相关协议 ####################### -->
<stream:stream xmlns:stream="http://etherx.jabber.org/streams"
        xmlns="jabber:client" from="127.0.0.1" id="e38900bc" xml:lang="en"
        version="1.0">
<!--
xmlns 表示通信客户端
from 客户端的地址(来源)
id
lang 通信语言
-->
<stream:features>
    <!-- 开始tls协议[TLS]的频道加密方法 -->
    <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"></starttls>
    <!-- 加密技术、安全证书 -->
    <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
        <mechanism>DIGEST-MD5</mechanism>
        <mechanism>PLAIN</mechanism>
        <mechanism>ANONYMOUS</mechanism>
        <mechanism>CRAM-MD5</mechanism>
    </mechanisms>
    <!-- 采用压缩技术 -->
    <compression xmlns="http://jabber.org/features/compress">
        <method>zlib</method>
    </compression>
    <!-- 权限 -->
    <auth xmlns="http://jabber.org/features/iq-auth" />
    <!-- 注册 -->
    <register xmlns="http://jabber.org/features/iq-register" />
</stream:features>

关于TSL 参考:http://www.jabbercn.org/RFC3920

1TSL协议遵循以下规则:

A、 一个遵守本协议的初始化实体必须(MUST)在初始化流的头信息中包含一个’version’属性并把值设为“1.0”。

B、 如果TLS握手发生在两个服务器之间,除非服务器声称的DNS主机名已经被解析,通信不能(MUST NOT)继续进行。

C、 当一个遵守本协议的接收实体接收了一个初始化流(它的头信息中包含一个’version’属性并且值设为“1.0”),在发送应答流的的头信息(其中包含 版本标记)之后,它必须发送(MUST)<starttls/>元素(名字空间为 ‘urn:ietf:params:xml:ns:xmpp-tls’)以及其他它支持的流特性。

D、 如果初始化实体选择使用TLS,TLS握手必须在SASL握手之前完成;这个顺序用于帮助保护SASL握手时发送的认证信息的安全,同时可以在必要的时候在TLS握手之前为SASL外部机制提供证书。

E、 TLS握手期间,一个实体不能(MUST NOT)在流的根元素中发送任何空格符号作为元素的分隔符(在下面的TLS示例中的任何空格符都仅仅是为了便于阅读);这个禁令用来帮助确保安全层字节精度。

F、 接收实体必须(MUST)在发送<proceed/> 元素的关闭符号”>” 之后立刻开始TLS协商。初始化实体必须(MUST)在从接收实体接收到<proceed/> 元素的关闭符号”>” 之后立刻开始TLS协商。

G、 初始化实体必须(MUST)验证接收实体出示的证书;关于证书验证流程参见Certificate Validation ( 第十四章第二节)。

H、 证书必须(MUST)检查初始化实体(比如一个用户)提供的主机名;而不是通过DNS系统解析出来的主机名;例如,如果用户指定一个主机 名”example.com”而一个DNS SRV [SRV]查询返回”im.example.com”,证书必须(MUST)检查”example.com”.如果任何种类的XMPP实体(例如客户端或 服务器)的JID出现在一个证书里,它必须(MUST)表现为一个别名实体里面的UTF8字符串,存在于subjectAltName之中。如何使用 [ASN.1] 对象标识符 “id-on-xmppAddr” 定义在本文的第五章第一节第一小节。

I、 如果 TLS 握手成功了,接收实体必须(MUST) 丢弃TLS 生效之前从初始化实体得到的任何不可靠的信息

J、 如果 TLS 握手成功了,初始化实体必须(MUST) 丢弃TLS 生效之前从接收实体得到的任何不可靠的信息

K、 如果 TLS 握手成功了,接收实体不能(MUST NOT)在流重新开始的时候通过提供其他的流特性来向初始化实体提供 STARTTLS 扩展

L、 如果 TLS 握手成功了,初始化实体必须(MUST)继续进行SASL握手

M、 如果 TLS 握手失败了,接收实体必须(MUST)终止XML流和相应的TCP连接。

N、 关于必须(MUST)支持的机制,参照 Mandatory-to-Implement Technologies (第十四章第七节) 。

2、当一个初始化实体用TLS保护一个和接收实体之间的流,其步骤如下:

A. 初始化实体打开一个TCP连接,发送一个打开的XML流头信息(其’version’属性设置为”1.0″)给接收实体以初始化一个流。

B. 接收实体打开一个TCP连接,发送一个XML流头信息(其’version’属性设置为”1.0″)给初始化实体作为应答。

C. 接收实体向初始化实体提议STARTTLS范围(包括其他支持的流特性),如果TLS对于和接收实体交互是必需的,它应该(SHOULD)在<starttls/>元素中包含子元素<required/>

D. 初始化实体发出STARTTLS命令(例如, 一个符合’urn:ietf:params:xml:ns:xmpp-tls’名字空间的 <starttls/> 元素) 以通知接收实体它希望开始一个TLS握手来保护流。

E. 接收实体必须(MUST)以’urn:ietf:params:xml:ns:xmpp-tls’名字空间中的<proceed/>元素 或<failure/>元素应答。如果失败,接收实体必须(MUST)终止XML流和相应的TCP连接。如果继续进行,接收实体必须 (MUST)尝试通过TCP连接完成TLS握手并且在TLS握手完成之前不能(MUST NOT)发送任何其他XML数据。

F. 初始化实体和接收实体尝试完成TLS握手。(要符合[TLS]规范)

G. 如果 TLS 握手不成功, 接收实体必须(MUST)终止 TCP 连接. 如果 TLS 握手成功, 初始化实体必须(MUST)发送给接收实体一个打开的XML流头信息来初始化一个新的流(先发送一个关闭标签</stream>是不必要的, 因为接收实体和初始化实体必须(MUST)确保原来的流在TLS握手成功之后被关闭) 。

H. 在从初始化实体收到新的流头信息之后,接收实体必须(MUST)发送一个新的XML流头信息给初始化实体作为应答,其中应包含可用的特性但不包含STATRTTLS特性。

[转载]Jwchat 的安装和配置、Service unavailable、Authorization failed问题汇总 - hoojo - 博客园

mikel阅读(738)

来源: [转载]Jwchat 的安装和配置、Service unavailable、Authorization failed问题汇总 – hoojo – 博客园

上一篇介绍了Openfire开源聊天IM服务器的安装:http://www.cnblogs.com/hoojo/archive/2012/05/17/2506769.html

这篇文章介绍Jwchat的安装和配置

 

首先Jwchat的配置和安装需要具备的环境:

Tomcat 5.0.28+/Tomcat 6

JDK 1.6+

Openfire 3.7.1

1、 下载jwchat工程文件

下载站点:http://blog.jwchat.org/jwchat/download/

Zip下载:http://downloads.sourceforge.net/jwchat/jwchat-1.0.zip?use_mirror=

 

2、 下载完成后,将jwchat-1.0.zip解压到你的tomcat的webapps目录,将jwchat-1.0命名为jwchat,如果不这样的话,可能会出现错误,如Authorization failed。至少这样会方便你访问jwchat工程。

然后将index.html.zh_CN等这样带有*.后缀.zh_CN的这样的文件的.zh_CN都删掉,进行重命名。.zh_CN是表示中文版的,当然你也可以直接将*.后缀.后缀的文件进行重命名,那样就是默认的英文版的了。

批量命名工具类:

package com.hoo.util;

import java.io.File;

/**
 * <b>function:</b> 文件命名工具类
 * @author hoojo
 * @createDate 2012-5-14 下午01:58:14
 * @file FileRenameUtils.java
 * @package com.hoo.util
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public abstract class FileRenameUtils {

    private final static String FILE_PATH = "D:\\apache-tomcat-6.0.33\\webapps\\jwchat";

    /**
     * <b>function:</b> 将指定目录下的文件的type类型的文件,进行重命名,命名后的文件将去掉type
     * <p>example: 如果type = html; index.html.html -> index.html</p>
     * <p>example: 如果type = zh_CN; index.html.zh_CN -> index.html</p>
     * @author hoojo
     * @createDate 2012-5-16 下午02:16:48
     * @param path
     * @param type
     */
    public static void rename(String path, String type) {
        if (path == null || "".equals(path)) {
            path = FILE_PATH;
        }
        File dir = new File(path);
        File[] list = dir.listFiles();
        for (File file : list) {
            String name = file.getName();
            String[] s = name.split("\\.");
            if (s.length == 3 && type.equals(s[2])) {
                System.out.println(s[0] + "--" + s[1] + "--" + s[2]);
                file.renameTo(new File(path + "/" + s[0] + "." + s[1]));
            }
        }
    }

    public static void main(String[] args) {
    FileRenameUtils.rename("D:\\apache-tomcat-6.0.33\\webapps\\jwchat", "zh_CN");
    }
}

3、 下载JabberHTTPBind这个包,因为直接下载的jwchat没有WEB-INF、web.xml是无法运行的。

JabberHTTPBind是jwchat进行http bind通信的一种方式,它可以让jwchat和openfire进行链接通信。

站点:http://blog.jwchat.org/jhb/

下载地址:http://blog.jwchat.org/download/JabberHTTPBind-1.1.1.zip

JabberHTTPBind会依赖xalan的library库

下载站点:http://xml.apache.org/xalan-j/downloads.html

下载目录:http://labs.renren.com/apache-mirror/xml/xalan-j/

 

4、 下载完成后,将JabberHTTPBind的zip解压出来的WEB-INF、META-INF一并放到刚才的jwchat目录中,并且将刚才下载的 xalan的xalan.jar,serializer.jar, xercesImpl.jar, xml-apis.jar放到webapps\jwchat\WEB-INF\lib目录下即可。

 

5、 修改jwchat目录中的相关配置

修改config.js文件

var BACKENDS =
[
        {
            ……
        },
        {
            ……
        },
        {
            name:"Open Relay",
            description:"HTTP Binding backend that allows connecting to any jabber server",
            httpbase:"/JHB/", /* 修改这里为:/jwchat/JHB/ */
            type:"binding",
            default_server: SITENAME
        },
        {
            ……
        }
];

修改WEB-INF目录下的web.xml文件

<servlet-mapping>
        <servlet-name>Jabber HTTP Binding Servlet</servlet-name>
        <url-pattern>/</url-pattern>
         url-pattern修改为:/JHB/
         <!-- 这里的修改主页是对应上面的config.js,如果config.js的httpbase配置是/jwchat/,那这里的就不用修改了 -->
</servlet-mapping>

6、 启动tomcat后,访问http://localhost:8080/jwchat/

如果登录出现Service unavailable这个问题,那么会有以下几种情况:

A、 表明服务器不可用,可能是openfire服务器没有启动,

B、 webapps\jwchat \config.js的配置有问题,如var SITENAME = “localhost”;和openfire服务器地址没有对应

C、 伴随出现:Exception in thread “Thread-34” javax.xml.transform.TransformerFactoryConfigurationError: Provider org.apache.xalan.processor.TransformerFactoryImpl not found异常,可能是tomcat版本低于tomcat6或是jwchat缺少相应的jar包,如缺少xml的serializer.jar、 xalan.jar、xercesImpl.jar、xml-apis.jar

D、 如果在满足了c步骤,有添加jra包还出现Exception in thread “Thread-34” javax.xml.transform.TransformerFactoryConfigurationError: Provider org.apache.xalan.processor.TransformerFactoryImpl not found异常,建议删除tomcat/work目录下的缓存,然后重启tomcat试试

 

7、 如果登录出现Authorization failed验证失败,那么有以下几种可能的情况:

A、 用户没有注册

B、 openfire的证书(C:\Program Files\openfire\resources\security)没有安装到相应的jdk的C:\Program Files\Java\jre6\lib\security目录下

如果出现这种异常信息:javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed也表明是安全证书的问题;

关于解决ssl验证,网上有人说在jsjac.js中的if(this.has_sasl) 这行前面加上this.has_sasl = false;来取消ssl安全证书的验证。

C、 如果你的工程名称不是jwchat,建议把它修改成jwchat并且修改config.xml的相关链接的配置(httpbase)

D、 还有可能是你当前的用户没有注册,这个时候你可以注册一个用户或是在openfire控制台的用户组中添加一个用户,然后再等了看看是否存在这个问题。

 

8、 修改服务器名称

点击服务器à服务器管理器à编辑属性 修改服务器名称

image

修改后的服务器名称

image

出现叹号,我们要删除安全证书,点击服务器à服务器设置à服务器安全证书删掉这里的证书。

image

删除后,在当前页面会出现提示,然后按照提示点击相应的链接,重启服务器,然后登陆,再生成证书

image

生成证书需要点时间,然后生成完成后,手动重启openfire服务器,再次登陆发现警告没有了。

image

9、 在服务器端增加配置

xmpp.httpbind.client.requests.polling = 0

xmpp.httpbind.client.requests.wait = 10

Openfire 的安装和配置

mikel阅读(963)

1、 下载最新的openfire安装文件

官方下载站点:http://www.igniterealtime.org/downloads/index.jsp#openfire

下载地址:

Exe:http://www.igniterealtime.org/downloads/download-landing.jsp?file=openfire/openfire_3_7_1.exe

ZIP: http://www.igniterealtime.org/downloads/download-landing.jsp?file=openfire/openfire_3_7_1.zip

我使用的是zip解压版的安装文件。

其中openfire是服务器,下面还有一个spark,这个是一个XMPP协议通信聊天的CS的IM软件,它可以通过openfire进行聊天对话。

 

2、 下载完成后,如果你下载的是exe文件,执行你的安装文件,进行安装。这里我是zip的文件。解压后,复制openfire目录到C:\Program Files\目录下;一定要在C:\Program Files\目录下的;这样openfire就安装完成了。

 

3、 下面我们启动openfire服务器,并配置它。在C:\Program Files\openfire\bin目录下有一个电灯泡的openfire.exe文件,双击执行,启动完成后可以看到

image

4、 点击Launch Admin按钮进入http://127.0.0.1:9090/setup/index.jsp页面,配置openfire服务器

 

5、 选择语言 中文简体

image

点击continue进入

 

6、 配置服务器域名

image

如果你是本地访问,那么你可以不修改或是使用localhost、127.0.0.1的方式

如果你用于外网或局域网访问,那么你的地址配置成外网或局域网地址

 

7、 选择数据库

image

选择openfire自带的,当然你也可以选择你的数据库类型。如Oracle、SQLServer、MySQL等。如果openfire没有带 jdbc的连接驱动,你需要添加连接数据库的jdbc驱动;驱动放在C:\Program Files\openfire\lib目录下

 

8、 选择特性配置,默认即可

image

 

9、 管理员邮件,可以跳过这步

image

 

10、 安装完成

image

进入管理员控制台页面

 

11、 进入http://127.0.0.1:9090/login.jsp页面后,输入admin、密码admin登陆进入

image

 

12、 进入后可以看到

image

服务器名称就是jwchat的连接地址;你可以使用Spark、jwchat链接这个地址进行IM通信聊天……

至此,openfire的安装和配置已经完成。下一篇文章开始完成jwchat的安装和配置。

如果你需要更换服务器名称ip,请看下一篇文章!

unity+高通vuforia开发增强现实(AR)教程(二)

mikel阅读(1349)

1、进入https://developer.vuforia.com选择Resource,我们可以看到高通提供多种版本的开发包,这里我们选择

 

2、下载好后导入unity,将下载好的识别图的unity包也导入进来

3、删掉mai camera,搜索AR Camera并将其拖到Hierarchy,同样的将ImageTarget也拖进来,对ImageTarget进行修改,Data Set修改为识别图的unity包的名字,其他参数大家应该都能明白,这里不再赘述

4、对AR Camera进行修改,将你要使用的数据勾选上就可以了

5、将你要显示的图片/文字/模型等位置调整好后拖到ImageTarget下就OK啦~\(≧▽≦)/~

哈哈,是不是很简单呢?下一期我会讲到关于视频的叠加,大家可以自己尝试分析高通给的案例包(网站上有,自己找找),制作更多好玩的AR

版权声明:本文为博主原创文章,未经博主允许不得转载。

unity+高通vuforia开发增强现实(AR)教程(一)

mikel阅读(1151)

增强现实(Augmented Reality,简称AR),是在虚拟现实的基础上发展起来的新技术,也被称之为混合现实。是通过计算机系统提供的信息增加用户对现实世界感知的技术,将 虚拟的信息应用到真实世界,并将计算机生成的虚拟物体、场景或系统提示信息叠加到真实场景中,从而实现对现实的增强。
上一段是百度的=。=不过只看文字估计有的童鞋还是不太明白,没关系,看两个视频你就知道了。戳这里:美女透视  汽车展示(都是我做的demo,欢迎大家一起探讨改进)

增强现实(AR)在国内也兴起有一段时间了,做了一年的AR开发,真心觉得用高通的那一套要实现最基本的功能很简单,当然要做出很棒的AR,仍需同 志们努力啊。现在研究AR的人也越来越多了,我觉得把信息(注意是信息,不是技术,真心不难,连行代码都木有,所以大家发明创造的机会来了)贡献出来让大 家一起做好玩的AR也很不错吧。作为一个习惯性伸手党,我写的教程会尽量让懂unity的人都能做自己的AR,接下来我们就当是做一个小玩具吧。

首先我们当然不可能现学open cv来实现识别算法和三维注册跟踪这类算法了,但是我们有很多可以选择的开发工具,其中高通是效果比较好的,而且免费哦大笑

那么我们要先到https://developer.vuforia.com注册账号(注意密码必须有大小写和数字,否则注册不成功)生成识别图的unity包。

1、选择target manager

2、选择create database创建你自己的识别图数据

3、点选进去之后选add target

4、嘿嘿,识别图生成好了,点选之后选择下载

5、选择unity editor,然后create,就会自动下载unity包了,这个包导入unity就可以做AR了!

高通是通过在图片上注册识别点来进行识别的,所以识别度与颜色没有关系。图片越复杂识别点越多,识别效果也就越好,所以相似的图片可能识别点分布相 近导致识别效果差,我们可以通过添加文字的方式来区别(汉字有多复杂大家自行脑补(╯▽╰))。我选择的这张识别图还好,四颗星,哈哈,黄色的小叉就是识 别点了。

版权声明:本文为博主原创文章,未经博主允许不得转载。

[转载]Unity利用高通sdk制作AR增强现实--茶壶(亲测) unity圣典(转) - 官方教程 - AR in China-增强现实中国技术论坛 - AR in China 增强现实中国

mikel阅读(813)

Unity利用高通sdk制作AR增强现实–茶壶(亲测) unity圣典(转) ,AR in China-增强现实中国技术论坛

来源: [转载]Unity利用高通sdk制作AR增强现实–茶壶(亲测) unity圣典(转) – 官方教程 – AR in China-增强现实中国技术论坛 – AR in China 增强现实中国1.下载Unity Extension
在这里
https://ar.qualcomm.at/qdevnet/sdk/ios 注册,这个是必须的

或者到asset store里找”Vuforia“,一样是要注册的
解压缩,安装

2.新建项目,新建项目的时候需要导入两个包:

  •        qcar-unity-ios-1-5-9.unitypackage: the base QCAR extension
  •        qcar-unity-imagetargets-ios1-5-9.unitypackage: a sample project using Image Targets


项目建完应该这样的:

2.1 选择 main Camera,删除它,因为你只需要一个相机
2.2 在Qualcomm Augmented Reality 下 有 Pfefabs 文件夹,我们拖入一个ARcamera到场景中去
2.3 拖入ImageTarget到场景中去,在 Hierarchy区域中选择之。
其属性应该这样的:

ImageTarget Behaviour 的项目中 ImageTarget 可以有两项选择,我们选择chips哪个,就是都是木头片的那个。

2.4 我们要往上放3D模型了,最简单的是从项目文件里拖一个teapot过去

2.5 接下来是一些设置工作,输出ios

正确填写bundle  属性,记住 要唯一
设定好了以后,File->Build;Run。
经过一个漫长的编译过程,Unity 应该自动打开你的Xcode
对着屏幕来一张。

Unity3D AR技术 vuforia SDK - 脱莫柔 - 博客园

mikel阅读(1006)

来源: Unity3D AR技术 vuforia SDK – 脱莫柔 – 博客园

原创文章如需转载请注明:转载自 脱莫柔Unity3D学习之旅 QQ群:【119706192】 本文链接地址: Unity3D AR技术 vuforia SDK

公司新项目要使用ar技术(增强现实),网上搜了些相关资料发现使用最多的就是高通的vuforiaSDK。

高通 vuforia 官网 (https://developer.vuforia.com)目前最新版本是2.0 (windows平台unity-2.0版本经尝试多次无法安装,请进QQ群(119706192)群共享中下载1.5版(vuforia-unity-Android-1-5-10.exe))

另外网上教材全是英文,而且全是英文,也没有告知如果设置自己的识别图(ImageTarget)。

中文网上教程少的可怜,一个人写的帖子被各种转载,人家原创写“下篇继续”,他们抄的也“下篇继续”,人家原创真的就在下篇继续了,抄袭的就果断太监了~

例子1:(本例子以window平台下unity – Android 1.5版本为例)

1.下载、安装sdk。安装完成后会在安装目录获得一些unitypackage资源包.

2.新建一个unity项目,导入一下两个资源包:

vuforia-Android-1-5-10.unitypackage

vuforia-imagetargets-android-1-5-10.unitypackage

3.删除自带的main camera,将AR Camera(Qualcomm Augmented Reality → Prefabs→AR Camera)托人场景。

4.接下来拖入要被识别图的背景图片-ImageTarget(Qualcomm Augmented Reality → Prefabs→ImageTarget),应用会通过检测摄像头拍摄的现实世界画面,与此图进行对比。

5.选择默认识别图:

①、选择ImageTarget,设置Image Target Behaviour(Script)组件的Data Set属性,本例子我们选StonesAndChips。

②、选择AR Camera,设置Data Set Load Behaviour(Script)组件的Activate Data Set属性,要与ImageTarget中选择的DataSet对应,所以也选择StonesAndChips,另外要对下面的 LOAD Data Set StonesAndChips 打勾。

6.拖入模型,最好使模型成为ImageTarget的子物体,摆放好模型的位置。

7.发布到android平台,真机运行。电脑中打开这张石子图片,直接拿手机对着显示器拍摄就能看到效果。


进阶:设置自己的IamgeTarget

1.登录vuforia 官网 (https://developer.vuforia.com),注册一个账户(密码必须含有大写字母、小写字母、数字)。

2.打开资源管理页(https://developer.vuforia.com/target-manager),Create Database 创建自己的目录。

3.Add Target 上传添加识别图。

4.选择上传的识别图,点击Down 下载资源包。

5.导入资源包。

6.设置自己的识别图。请参考例子1中的第五步。