导航:首页 > 操作系统 > androidndk回调

androidndk回调

发布时间:2023-02-09 02:22:20

A. android NDK 用C语言好还是C++好

C++好,对于NDK来说,C++比C语言在与java的回调机制上更加很好的配合,目前来说,大部分比较高级的程序都是利用C++来写的,既能具备JAVA的方便又能具备C语言的执行效率高,用C++好一些

Android NDK 是在SDK前面又加上了“原生”二字,即Native Development Kit,因此又被Google称为“NDK”。
众所周知,Android程序运行在Dalvik虚拟机中,NDK允许用户使用类似C / C++之类的原生代码语言执行部分程序。
NDK包括了:
从C / C++生成原生代码库所需要的工具和build files。
将一致的原生库嵌入可以在Android设备上部署的应用程序包文件(application packages files ,即.apk文件)中。
支持所有未来Android平台的一些列原生系统头文件和库
为何要用到NDK?
概括来说主要分为以下几种情况:
1. 代码的保护,由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。
2. 在NDK中调用第三方C/C++库,因为大部分的开源库都是用C/C++代码编写的。
3. 便于移植,用C/C++写的库可以方便在其他的嵌入式平台上再次使用。

B. 安卓开发一定要用 Java 吗,其他语言开发方便吗

我可以很肯定的跟你说:是的,必须是的。基于java这门语言作为应用层的开发语言的优势与目的我就不说了,网上一大堆。结合我浅薄的android开发经验来跟你说说:


1、应用层的开发是使用java语言跟xml布局以及充当小型数据库功能的特点,你必须得会java跟xml,这是基础。xml就没什么好介绍的,java的话必须得掌握它的多线程操作机制以及事件驱动机制,回调机制。

如果是安卓系统的话:一般是Java开发,但是会调用C的代码; 如果是安卓软件的话:必须是Java,因为安卓系统原始都是Java开发。Android主流开发语言是Java,但也可以使用C、C++开发, 即使用Android NDK,不过使用NDK编程有一些劣势,比如程 序更加复杂,兼容性难以保障,无法访问Framework API,Debug 难度更大等。所以一般还是用Java,只是有时候会在一些核心代码上用C和C++来提高执行效率。


以上均是我个人原创的学习以及开发经验,这只是建议,大家根据自己的实际经验操作吧!

C. 如何在Android studio下调试ndk

千锋扣丁学堂Android开发为您解答:第一步:下载AndroidNDK。第二步:为project设置ndk路径,在local.properties中,添加ndk.dir=。第三步:修改build.gradle文件。第四步:创建jni文件。第五步:创建测试类文件。第六步:创建.h文件。创建.cpp文件。第七步:进行测试

D. 如何在Android NDK中调用第三方库文件

如何在Android NDK中调用第三方库文件(.so) 1.在project/jni目录下创建prebuilt子目录(目录名可自定义).

2.将第三方.so放到prebuilt中,并创建Android.mk, 内容如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := xxx

LOCAL_SRC_FILES := libxxx.so

include $(PREBUILT_SHARED_LIBRARY)

3.在project/jni/Android.mk中加入

LOCAL_SHARED_LIBRARIES := xxx

4.在project/jni/android.mk的最后加入

include $(LOCAL_PATH)/prebuilt/Android.mk

5.运行cygwin, 到project目录下, 运行$NDK/ndk-build

E. 这个程序用了模板,但是我不懂其中的参数,是什么意思呐,还有d=new T*[n];语句是什么意思

为了在Mac OS X中安装运行MacPort端口,系统必须要已经安装苹果的“Command Line Developer Tools”(命令行开发者工具)。Xcode 4及以后版本的用户首先需要通过启动或运行Xcode接受Xcode EULA。
xcodebuild -license
下载安装MacPort
注意:如果是Homebrew用户,应该先卸载Homebrew。因为Homebrew不兼容MacPort。
同时执行MacPort的“selfupdate”命令以确保安装最新的发布版本。
sudo port -v selfupdate
当更新完成之后,使用MacPort在命令行中安装python依赖(dependencies)
sudo port install python27 py27-yaml py27-cheetah
你会看到如下所示:
下载llvm-3.3,解压至$HOME/bin目录。如果没有bin目录,请创建一个bin目录,将未解压的ZIP压缩包重命名为“clang+llvm-3.3”。
最后目录如下所示:/Users/guanghui/bin/clang+llvm-3.3(guanhui是本机的主目录名字)
样本代码
绑定生成器资源库中包括一个样本测试用例。打开bindings-generator/test/simple_test文件夹
配置
根据自己的环境个性化设置“test/userconf.ini”和“test/user.cfg”文件。
注意:应该移除后缀为“.sample”的文件如“user.cfg.sample”和“userconf.ini.sample”
[DEFAULT]
androidndkdir=/Users/iven/Dev/android-ndk-r8c
clangllvmdir=/Users/iven/Dev/clang+llvm-3.1-x86_64-apple-darwin11
cxxgeneratordir=/Users/iven/Dev/bindings-generator-master
user.cfg配置如下所示
PYTHON_BIN=/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin/ python2.7
运行测试样本
./test.sh
如果环境设置正确,你会看到如下所示:
Errors in parsing headers:
1. <severity = Warning,
location =<SourceLocation file None, line 0, column 0>,
details = "argument unusedring compilation: '-nostdinc++'">
不用担心这个警告,你已完成运行,测试用例会创建一个包含3个文件的“simple_test_bindings”目录。
一个绑定类的.hpp头文件
一个实现绑定类的.cpp文件
一个介绍如何(从Java脚本)调用C++类暴露方法的.js文件。
运行测试
Create a JS base Cocos2d-x project. 创建基于JS的Cocos2d-x项目
将“simple_Test folder”文件夹和“simple_test_binding”文件夹添加到项目中
修改“autogentestbindings.cpp”中的注册函数如下:
void register_all_autogentestbindings(JSContext* cx, JSObject* obj) {
jsval nsval;
JSObject *ns;
JS_GetProperty(cx, obj, "ts",&nsval);
if (nsval == JSVAL_VOID) {
ns = JS_NewObject(cx, NULL, NULL, NULL);
nsval = OBJECT_TO_JSVAL(ns);
JS_SetProperty(cx, obj, "ts",&nsval);
} else {
JS_ValueToObject(cx,nsval, &ns);
}
obj = ns;
js_register_autogentestbindings_SimpleNativeClass(cx, obj);
}
注意:如果你将“ts”添加到“test.ini”文件中的“target_namespace”变量里,便会自动生成代码。无需修改。
target_namespace =ts
在“AppDelegate”中注册
包含头文件“autogentestbindings.hpp”然后注册回调函数:
sc->addRegisterCallback(register_all_autogentestbindings);
在“hello.js”文件适当地方增加以下代码。本机将“init f”函数放在第一个场景。
var myClass=new ts.SimpleNativeClass();
var myStr=myClass.returnsACString();
var label = cc.LabelTTF.create(myStr, "Helvetica", 20.0);
限制
绑定生成器存在以下两个限制
自变量数字参数无法工作,所以需要手动编写包装器
代表类无法工作,所以需要手动绑定,详见下一部分。
手动 JSB 绑定
本指南将介绍利用Cocos2d-x 2.14模板如何在自己的项目中实现JSB绑定。
首先用Cocos2d-js模板创建项目。其次,我们会介绍如何一步一步从JS调用本地函数。最后你便会学会如何从本地代码调用JS代码了。
现在让我们开始!本机使用的Mac OS X作为开发环境。
步骤1. 用Cocos2dx-js模板创建新项目,同时新建一个即将绑定至JS的C++类。
将项目命名为“JSBinding”然后点击“Next”、“ Create”
新建一个类然后实现这个类,等会再将其绑定至JS。
按“command+N”新建一个C++类并命名为“JSBinding”,路径为“OS X\C and C++\C++ Class”。
将以下代码添加到“JSBinding.h”文件中。
#include "cocos2d.h"
#include "ScriptingCore.h"
// Define a namespace to manage your code and make your code clearly
namespace JSB {
class JSBinding: public cocos2d::CCObject
{
public:
static cocos2d::CCScene* scene();
virtual bool init();
CREATE_FUNC(JSBinding);
void functionTest();
};
}
现在实现JSBinding.cpp中的类。如下所示:
bool JSB::JSBinding::init(){
bool bRef = false;
do{
cocos2d::CCLog("JSB init...");
bRef = true;
} while (0);
return bRef;
}
void JSB::JSBinding::functionTest(){
cocos2d::CCLog("Function test...");
}
步骤2. 将C++代码绑定至Java脚本代码
按“command+N”新建C++类,然后命名“JSB_AUTO”路径“OS X\C and C++\C++ Class”。
往“JSB_AUTO.h”文件中增加一些代码
#include "jsapi.h"
#include "jsfriendapi.h"
#include "ScriptingCore.h"
#include "JSBinding.h"
void register_all(JSContext* cx, JSObject* obj);
然后注意“JSB_AUTO.cpp”的实现。
#include "jsapi.h"
#include "jsfriendapi.h"
#include "ScriptingCore.h"
#include "JSBinding.h"
void register_all(JSContext* cx, JSObject* obj);
然后注意“JSB_AUTO.cpp”的实现。
#include "cocos2d.h"
#include "cocos2d_specifics.hpp"
// Binding specific object by defining JSClass
JSClass* jsb_class;
JSObject* jsb_prototype;
// This function is mapping the function “functionTest” in “JSBinding.cpp”
JSBool js_functionTest(JSContext* cx, uint32_t argc, jsval* vp){
JSBool ok = JS_TRUE;
JSObject* obj = NULL;
JSB::JSBinding* cobj = NULL;
obj = JS_THIS_OBJECT(cx, vp);
js_proxy_t* proxy = jsb_get_js_proxy(obj);
cobj = (JSB::JSBinding* )(proxy ? proxy->ptr : NULL);
JSB_PRECONDITION2(cobj, cx, JS_FALSE, "Invalid Native Object");
if (argc == 0) {
cobj->functionTest();
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return ok;
}
JS_ReportError(cx, "Wrong number of arguments");
return JS_FALSE;
}
JSBool js_constructor(JSContext* cx, uint32_t argc, jsval* vp){
cocos2d::CCLog("JS Constructor...");
if (argc == 0) {
JSB::JSBinding* cobj = new JSB::JSBinding();
cocos2d::CCObject* ccobj = dynamic_cast<cocos2d::CCObject*>(cobj);
if (ccobj) {
ccobj->autorelease();
}
TypeTest<JSB::JSBinding> t;
js_type_class_t* typeClass;
uint32_t typeId = t.s_id();
HASH_FIND_INT(_js_global_type_ht, &typeId, typeClass);
assert(typeClass);
JSObject* obj = JS_NewObject(cx, typeClass->jsclass, typeClass->proto, typeClass->parentProto);
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
js_proxy_t* p = jsb_new_proxy(cobj, obj);
JS_AddNamedObjectRoot(cx, &p->obj, "JSB::JSBinding");
return JS_TRUE;
}
JS_ReportError(cx, "Wrong number of arguments: %d, was expecting: %d", argc, 0);
return JS_FALSE;
}
// This function is mapping the function “create” when using JavaScript code
JSBool js_create(JSContext* cx, uint32_t argc, jsval* vp){
cocos2d::CCLog("js is creating...");
if (argc == 0) {
JSB::JSBinding* ret = JSB::JSBinding::create();
jsval jsret;
do{
if (ret) {
js_proxy_t* proxy = js_get_or_create_proxy<JSB::JSBinding>(cx, ret);
jsret = OBJECT_TO_JSVAL(proxy->obj);
}
else{
jsret = JSVAL_NULL;
}
} while(0);
JS_SET_RVAL(cx, vp, jsret);
return JS_FALSE;
}
JS_ReportError(cx, "Wrong number of arguments");
return JS_FALSE;
}
void js_finalize(JSFreeOp* fop, JSObject* obj){
CCLOGINFO("JSBindings: finallizing JS object %p JSB", obj);
}
// Binding JSB type
void js_register(JSContext* cx, JSObject* global){
jsb_class = (JSClass *)calloc(1, sizeof(JSClass));
jsb_class->name = "JSBinding";
jsb_class->addProperty = JS_PropertyStub;
jsb_class->delProperty = JS_PropertyStub;
jsb_class->getProperty = JS_PropertyStub;
jsb_class->setProperty = JS_StrictPropertyStub;
jsb_class->enumerate = JS_EnumerateStub;
jsb_class->resolve = JS_ResolveStub;
jsb_class->convert = JS_ConvertStub;
jsb_class->finalize = js_finalize;
jsb_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);
static JSPropertySpec properties[] = {
{0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER}
};
// Binding functionTest function
static JSFunctionSpec funcs[] = {
JS_FN("functionTest", js_functionTest, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
JS_FS_END
};
// Binding create() function
static JSFunctionSpec st_funcs[] = {
JS_FN("create", js_create, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
JS_FS_END
};
// Binding constructor function and prototype
jsb_prototype = JS_InitClass(
cx, global,
NULL,
jsb_class,
js_constructor, 0,
properties,
funcs,
NULL,
st_funcs);
JSBool found;
JS_SetPropertyAttributes(cx, global, "JSB", JSPROP_ENUMERATE | JSPROP_READONLY, &found);
TypeTest<JSB::JSBinding> t;
js_type_class_t* p;
uint32_t typeId = t.s_id();
HASH_FIND_INT(_js_global_type_ht, &typeId, p);
if (!p) {
p = (js_type_class_t* )malloc(sizeof(_js_global_type_ht));
p->type = typeId;
p->jsclass = jsb_class;
p->proto = jsb_prototype;
p->parentProto = NULL;
HASH_ADD_INT(_js_global_type_ht, type, p);
}
}
// Binding JSB namespace so in JavaScript code JSB namespce can be recognized
void register_all(JSContext* cx, JSObject* obj){
jsval nsval;
JSObject* ns;
JS_GetProperty(cx, obj, "JS", &nsval);
if (nsval == JSVAL_VOID) {
ns = JS_NewObject(cx, NULL, NULL, NULL);
nsval = OBJECT_TO_JSVAL(ns);
JS_SetProperty(cx, obj, "JSB", &nsval);
}
else{
JS_ValueToObject(cx, nsval, &ns);
}
obj = ns;
js_register(cx, obj);
}
现在已经完成了大部分工作,但是我们需要在“SpiderMonkey”进行注册。
打开“AppDelegate.cpp”增加以下代码
ScriptingCore* sc = ScriptingCore::getInstance();
sc->addRegisterCallback(register_all); //add this line
步骤3. 内存管理
在register_all函数前增加两个新函数。
JSBool JSB_cocos2dx_retain(JSContext* cx, uint32_t argc, jsval *vp){
JSObject* thisObj = JS_THIS_OBJECT(cx, vp);
if (thisObj) {
js_proxy_t* proxy = jsb_get_js_proxy(thisObj);
if (proxy) {
((CCObject* )proxy->ptr)->retain();
CCLog("Retain succeed!");
return JS_TRUE;
}
}
JS_ReportError(cx, "Invaild native object");
return JS_FALSE;
}
JSBool JSB_cocos2dx_release(JSContext* cx, uint32_t argc, jsval *vp){
JSObject* thisObj = JS_THIS_OBJECT(cx, vp);
if (thisObj) {
js_proxy_t* proxy = jsb_get_js_proxy(thisObj);
if (proxy) {
((CCObject* )proxy->ptr)->release();
CCLog("Release succeed!");
return JS_TRUE;
}
}
JS_ReportError(cx, "Invaild native object");
return JS_FALSE;
}
在register_all函数中增加以下代码:
JS_DefineFunction(cx, jsb_prototype, "retain", JSB_cocos2dx_retain, 0, JSPROP_READONLY | JSPROP_PERMANENT);
JS_DefineFunction(cx, jsb_prototype, "retain", JSB_cocos2dx_release, 0, JSPROP_READONLY | JSPROP_PERMANENT);
步骤4. 使用C++代码回调Java脚本代码
在C++代码回调Java脚本代码之前增加一些代码至“hello.js”文件。
var testJSB = new JSB.JSBinding();
testJSB.callback = function(i, j){
log("JSB Callback" + i + j);
};
然后打开“JSBinding.cpp”在“functionTest”中增加一些代码。
js_proxy_t* p = jsb_get_native_proxy(this);
jsval retval;
jsval v[] = {
v[0] = UINT_TO_JSVAL(32),
v[1] = UINT_TO_JSVAL(88)
};
ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj),
"callback", 2, v, &retval);
使用“executeFunctionWithOwner()”函数简化函数调用程序
步骤5. 绑定测试
在“hello.js”文件中增加以下代码。
var testJSB = new JSB.JSBinding();
testJSB.retain();
testJSB.functionTest();
testJSB.release();
步骤6. 现在取出(check out)项目
如果你的绑定程序正确无误,将会在调试窗口看到如下界面:
恭喜你成功将JS绑定至本地代码!

F. 如何调试android NDK 交叉编译的cpp文件

主要讲一下具体的步骤,具体的ndk指令我就不说了,贴的文章都有:
首先是写一个.java文件,本例中是HprofDumper.java
具体如下:

public class HprofDumper {

public native boolean hprofDumper(String filename, String outname);
}

然后用命令javac HprofDumper.java 生成.class文件
再用javah HprofDumper 生成相应的.h文件

生成的.h文件如下
#include

#ifndef _Included_HprofDumper
#define _Included_HprofDumper
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jboolean JNICALL Java_HprofDumper_hprofDumper
(JNIEnv *, jobject, jstring, jstring);

#ifdef __cplusplus
}
#endif
#endif

然后只需要在对应的.cpp文件完成相应函数即可,核心代码如下:
#include "HprofDumper.h"
#include "hprof.h"

JNIEXPORT jboolean JNICALL Java_HprofDumper_hprofDumper
(JNIEnv *env, jobject obj, jstring in_file, jstring out_file)
{
const char *filename = env->GetStringUTFChars(in_file, 0);
const char *outname = env->GetStringUTFChars(out_file, 0);
return hprof_mp(filename, outname);
}
其中hprof_mp是纯c++代码,引入即可。
有一点需要注意,标红了已经,就是生成的.h文件函数并没具体形参名字,只有形参类型,在.cpp文件中要加入相应的形参名字,本例为env、 obj、 in_file和out_file。
还有一点c和c++的区别,就是env的使用。
本例中C++为env->GetStringUTFChars(in_file, 0);
如果是C就应该改为(env)->GetStringUTFChars(env,in_file, 0);
调用Java类型 : C中调用Java中的String类型为 jstring;

C语言方法名规则 : Java_完整包名类名_方法名(JNIEnv *env, jobject thiz), 注意完整的类名包名中包名的点要用 _ 代替;

参数介绍 : C语言方法中有两个重要的参数, JNIEnv *env, jobject thiz ;
-- JNIEnv参数 : 该参数代表Java环境, 通过这个环境可以调用Java中的方法;
-- jobject参数 : 该参数代表调用jni方法的类,;

调用jni.h中的NewStringUTF方法 : 该方法的作用是在C语言中创建一个Java语言中的String类型对象, jni.h中是这样定义的 jstring (*NewStringUTF)(JNIEnv*, const char*), JNIEnv 结构体中包含了 NewStringUTF 函数指针, 通过 JNIEnv 就可以调用这个方法;

完成代码编写后,在当前目录下完成Android.mk和Application.mk的编写
首先是Android.mk
本例中为:
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hprof-mper
LOCAL_C_INCLUDES += external/stlport/stlport
LOCAL_C_INCLUDES += bionic
LOCAL_C_INCLUDES += bionic/libstdc++/include
LOCAL_SRC_FILES := HprofDumper.cpp \
xx.cpp \
xx.cpp \
xx.cpp \
xx.cpp \
xx.cpp \
xx.cpp \
xxx.cpp
LOCAL_SHARED_LIBRARIES := libstlport
include $(BUILD_SHARED_LIBRARY)
注意标红的是最关键的,LOCAL_C_INCLUDES 顾名思义是需要的头文件的所在的目录,那三个参数主要为了引入STL,最重要!!LOCAL_SHARED_LIBRARIES 我一直生成失败就是没加这个参数,不光要引入头文件,还要引入具体的lib,这就是这个字段的作用。
具体字段的作用:
-- LOCAL_PATH : 代表mk文件所在的目录;
-- include $(CLEAR_VARS) : 编译工具函数, 通过该函数可以进行一些初始化操作;
-- LOCAL_MODULE : 编译后的 .so 后缀文件叫什么名字;
-- LOCAL_SRC_FILES: 指定编译的源文件名称;
-- include $(BUILD_SHARED_LIBRARY) : 告诉编译器需要生成动态库;

Applicaion.mk中就一行
APP_STL = stlport_static
表示使用stl静态库。

注意:我用了STL,大家没有用STL的当然不用引入这些啦~

G. “Android NDK ”是什么,在什么情况下使用

Android 应用是在dalvik虚拟机中运行的。NDK可以让你使用本地代码语言来开发应用,比如说C/C++,这种方法对某些类型的应用的是有好处的,可以充分利用本地代码和在某些情况下加速代码的执行。
对于绝大多数的应用来说,使用NDK并不是一个明智的选择,作为一个开发者,我们需要衡量它所带来的好处和缺点。使用本地代码并不一定可以使性能得到优化,但是通常使得应用代码变得复杂。一般来说,我们将应用中关键部分的代码用C/C++写,而不能由于我们习惯于用C/C++开发而把所有的代码都用C/C++来实现。
有下面这些特点的应用可以考虑使用NDK:
1 独立的,不和其他应用有关系的
2 频繁占用CPU但是申请的内存空间不是很大的操作,像信号的处理,物体的模拟等等
简单的用C/C++重写我们的代码是不会带来很大的性能提升的。
在考虑是否采用本地代码开发的时候,要结合应用的实际需求并且看看Android 的framework层是否提供了我们需要的API,但是用NDK可以充分利用本地已经有的代码。
Android framework提供下面两种方法来使用本地代码:
1 在Android framework的框架下面开发应用,使用JNI的方法来使用NDK本地方法提供的API。这样的好处就是我们可以很好的利用的Android的framework提供的框架,但是需要编写本地具体实现的代码。这样的APK可以在Android 1.5及其之后的版本上面运行。
2 写一个本地的Activity,在本地代码中实现生命回调函数,AndroidSDk提供了
类,这个类可以方便的让你在你的本地代码中实现回调函数(OnCreate,OnPause),从而当这些事件发生的时候处理。

H. android ndk怎么调用c实现的返回值为int指针类型

函数: int fun(int a,int b); 要定义指向该函数的指针 对比指向 int a; 的指针 int *p; p = &a; p的定义是怎么来的? 首先要保证p是一个指针类型 写下(*p), 然后,考虑下p的基类型, p的基类型就是变量a的类型int 将int 放在(*p)前面就行了

I. android ndk 怎么使用回调

Java代码如下(获取设备ANDROID_ID):
final String androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);

对应的c代码(相当蛋疼),注意如果是C++,需要把所有的(*env)->替换成env->,同时去掉第一个参数env

char *
get_android_id(JNIEnv *env, jobject mContext, jobject actObj)
{
char *szDevId = NULL;

if (!mContext) {
return szDevId;

阅读全文

与androidndk回调相关的资料

热点内容
邵氏3级电影 浏览:320
男主角叫安迪的电影 浏览:77
建德盛德电影院今日电影 浏览:89
谁有在线观看的网站 浏览:643
午夜不卡电影 浏览:760
python字符串unicode编码 浏览:6
电影加密的软件 浏览:728
鬼王镜奴的古装电影 浏览:35
python3module 浏览:497
韩国李彩谭作品 浏览:931
python爬虫gif 浏览:861
重生收母 浏览:539
都市之开局被10个老婆宠成 浏览:233
程序员两年应该多少工资 浏览:964
极盗者2在线免费观看 浏览:854
男男电影免费观看推荐 浏览:361
福建u盘加密联系方式 浏览:516
釜山行3免费完整观看国语 浏览:78
官神夏想几个老婆 浏览:249
看片网站知乎 浏览:60