當前位置:首頁 » 安卓系統 » androidjstring

androidjstring

發布時間: 2025-02-10 10:48:29

1. 如何在Android下使用JNI

1.引言
我們知道,Android系統的底層庫由c/c++編寫,上層Android應用程序通過java虛擬機調用底層介面,銜接底層c/c++庫與Java應用程序間的介面正是JNI(JavaNative Interface)。本文描述了如何在ubuntu下配置AndroidJNI的開發環境,以及如何編寫一個簡單的c函數庫和JNI介面,並通過編寫Java程序調用這些介面,最終運行在模擬器上的過程。

2.環境配置

2.1.安裝jdk1.6
(1)從jdk官方網站下載jdk-6u29-linux-i586.bin文件。
(2)執行jdk安裝文件
[html] view plainprint?
01.$chmod a+x jdk-6u29-linux-i586.bin
02.$jdk-6u29-linux-i586.bin
$chmod a+x jdk-6u29-linux-i586.bin
$jdk-6u29-linux-i586.bin
(3)配置jdk環境變數

[html] view plainprint?
01.$sudo vim /etc/profile
02.#JAVAEVIRENMENT
03.exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29
04.exportJRE_HOME=$JAVA_HOME/jre
05.exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
06.exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
$sudo vim /etc/profile
#JAVAEVIRENMENT
exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29
exportJRE_HOME=$JAVA_HOME/jre
exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
保存後退出編輯,並重啟系統。

(4)驗證安裝

[html] view plainprint?
01.$java -version
02.javaversion "1.6.0_29"
03.Java(TM)SE Runtime Environment (build 1.6.0_29-b11)
04.JavaHotSpot(TM) Server VM (build 20.4-b02, mixed mode)
05.$javah
06.用法:javah[選項]<類>
07.其中[選項]包括:
08.-help輸出此幫助消息並退出
09.-classpath<路徑>用於裝入類的路徑
10.-bootclasspath<路徑>用於裝入引導類的路徑
11.-d<目錄>輸出目錄
12.-o<文件>輸出文件(只能使用-d或-o中的一個)
13.-jni生成JNI樣式的頭文件(默認)
14.-version輸出版本信息
15.-verbose啟用詳細輸出
16.-force始終寫入輸出文件
17.使用全限定名稱指定<類>(例
18.如,java.lang.Object)。
$java -version
javaversion "1.6.0_29"
Java(TM)SE Runtime Environment (build 1.6.0_29-b11)
JavaHotSpot(TM) Server VM (build 20.4-b02, mixed mode)
$javah
用法:javah[選項]<類>
其中[選項]包括:
-help輸出此幫助消息並退出
-classpath<路徑>用於裝入類的路徑
-bootclasspath<路徑>用於裝入引導類的路徑
-d<目錄>輸出目錄
-o<文件>輸出文件(只能使用-d或-o中的一個)
-jni生成JNI樣式的頭文件(默認)
-version輸出版本信息
-verbose啟用詳細輸出
-force始終寫入輸出文件
使用全限定名稱指定<類>(例
如,java.lang.Object)。2.2.安裝android應用程序開發環境
ubuntu下安裝android應用程序開發環境與windows類似,依次安裝好以下軟體即可:
(1)Eclipse
(2)ADT
(3)AndroidSDK
與windows下安裝唯一不同的一點是,下載這些軟體的時候要下載Linux版本的安裝包。
安裝好以上android應用程序的開發環境後,還可以選擇是否需要配置emulator和adb工具的環境變數,以方便在進行JNI開發的時候使用。配置步驟如下:
把emulator所在目錄android-sdk-linux/tools以及adb所在目錄android-sdk-linux/platform-tools添加到環境變數中,android-sdk-linux指androidsdk安裝包android-sdk_rxx-linux的解壓目錄。
[plain] view plainprint?
01.$sudo vim /etc/profile
02.exportPATH=~/software/android/android-sdk-linux/tools:$PATH
03. exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH
$sudo vim /etc/profile
exportPATH=~/software/android/android-sdk-linux/tools:$PATH
exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH
編輯完畢後退出,並重啟生效。

2.3.安裝NDK
NDK是由android提供的編譯android本地代碼的一個工具。
(1)從androidndk官網http://developer.android.com/sdk/ndk/index.html下載ndk,目前最新版本為android-ndk-r6b-linux-x86.tar.bz2.
(2)解壓ndk到工作目錄:
[plain] view plainprint?
01.$tar -xvf android-ndk-r6b-linux-x86.tar.bz2
02.$sudo mv android-ndk-r6b /usr/local/ndk
$tar -xvf android-ndk-r6b-linux-x86.tar.bz2
$sudo mv android-ndk-r6b /usr/local/ndk
(3)設置ndk環境變數

[plain] view plainprint?
01.$sudo vim /etc/profile
02.exportPATH=/usr/local/ndk:$PATH
$sudo vim /etc/profile
exportPATH=/usr/local/ndk:$PATH

編輯完畢後保存退出,並重啟生效

(4)驗證安裝

[plain] view plainprint?
01.$ cd/usr/local/ndk/samples/hello-jni/
02.$ ndk-build
03.Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver
04.Gdbsetup : libs/armeabi/gdb.setup
05.Install : libhello-jni.so => libs/armeabi/libhello-jni.so
$ cd/usr/local/ndk/samples/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

3.JNI實現
我們需要定義一個符合JNI介面規范的c/c++介面,這個介面不用太復雜,例如輸出一個字元串。接下來,則需要把c/c++介面的代碼文件編譯成共享庫(動態庫).so文件,並放到模擬器的相關目錄下。最後,啟動Java應用程序,就可以看到最終效果了。

3.1.編寫Java應用程序代碼
(1)啟動Eclipse,新建android工程

Project:JNITest

Package:org.tonny.jni

Activity:JNITest

(2)編輯資源文件

編輯res/values/strings.xml文件如下:編輯res/layout/main.xml文件
我們在主界面上添加了一個EditText控制項和一個Button控制項。

(3)編輯JNITest.java文件


static表示在系統第一次載入類的時候,先執行這一段代碼,在這里表示載入動態庫libJNITest.so文件。

再看這一段:

[java] view plainprint?
01.privatenativeString GetReply();
privatenativeString GetReply();
native表示這個方法由本地代碼定義,需要通過jni介面調用本地c/c++代碼。

[java] view plainprint?
01.publicvoidonClick(View arg0) {
02.edtName.setText(reply);
03.}
publicvoidonClick(View arg0) {
edtName.setText(reply);
}

這段代碼表示點擊按鈕後,把native方法的返回的字元串顯示到EditText控制項。

(4)編譯工程,生成.class文件。

3.2.用javah工具生成符合JNI規范的c語言頭文件

在終端中,進入android工程所在的bin目錄

[plain] view plainprint?
01.$cd ~/project/Android/JNITest/bin
$cd ~/project/Android/JNITest/bin
我們用ls命令查看,可以看到bin目錄下有個classes目錄,其目錄結構為classes/org/tonny/jni,即classes的子目錄結構是android工程的包名org.tonny.jni。請注意,下面我們准備執行javah命令的時候,必須進入到org/tonny/jni的上級目錄,即classes目錄,否則javah會提示找不到相關的java類。

下面繼續:

[plain] view plainprint?
01.$cd classes
02.$javah org.tonny.jni.JNITest
03.$ls
04.org org_tonny_jni_JNITest.h
$cd classes
$javah org.tonny.jni.JNITest
$ls
org org_tonny_jni_JNITest.h

執行javahorg.tonny.jni.JNITest命令,在classes目錄下會生成org_tonny_jni_JNITest.h頭文件。如果不進入到classes目錄下的話,也可以這樣:

[plain] view plainprint?
01.$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest
$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest
-classpath 參數表示裝載類的目錄。

3.3.編寫c/c++代碼
生成org_tonny_jni_JNITest.h頭文件後,我們就可以編寫相應的函數代碼了。下面在android工程目錄下新建jni目錄,即~/project/Android/JNITest/jni,把org_tonny_jni_JNITest.h頭文件拷貝到jni目錄下,並在jni目錄下新建org_tonny_jni_JNITest.c文件,編輯代碼如下:

[cpp] view plainprint?
01.#include<jni.h>
02.#include<string.h>
03.#include"org_tonny_jni_JNITest.h"
04.
05.
06.JNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply
07.(JNIEnv *env, jobject obj){
08.return(*env)->NewStringUTF(env,(char*)"Hello,JNITest");
09.}
#include<jni.h>
#include<string.h>
#include"org_tonny_jni_JNITest.h"

JNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply
(JNIEnv *env, jobject obj){
return(*env)->NewStringUTF(env,(char*)"Hello,JNITest");
}

我們可以看到,該函數的實現相當簡單,返回一個字元串為:"Hello,JNITest"

3.4.編寫Android.mk文件
在~/project/Android/JNITest/jni目錄下新建Android.mk文件,android可以根據這個文件的編譯參數編譯模塊。編輯Android.mk文件如下:

[plain] view plainprint?
01.LOCAL_PATH:= $(call my-dir)
02.include$(CLEAR_VARS)
03.LOCAL_MODULE := libJNITest
04.LOCAL_SRC_FILES:= org_tonny_jni_JNITest.c
05.include$(BUILD_SHARED_LIBRARY)
LOCAL_PATH:= $(call my-dir)
include$(CLEAR_VARS)
LOCAL_MODULE := libJNITest
LOCAL_SRC_FILES:= org_tonny_jni_JNITest.c
include$(BUILD_SHARED_LIBRARY)

LOCAL_MODULE表示編譯的動態庫名稱

LOCAL_SRC_FILES 表示源代碼文件

3.5.用ndk工具編譯並生成.so文件
進入到JNITest的工程目錄,執行ndk-build命令即可生成libJNITest.so文件。

[plain] view plainprint?
01.$cd ~/project/Android/JNITest/
02.$ndk-build
03.Invalidattribute name:
04.package
05.Install : libJNITest.so => libs/armeabi/libJNITest.so
$cd ~/project/Android/JNITest/
$ndk-build
Invalidattribute name:
package
Install : libJNITest.so => libs/armeabi/libJNITest.so
可以看到,在工程目錄的libs/armeabi目錄下生成了libJNITest.so文件。

3.6.在模擬器上運行
(1)首先,我們把android模擬器啟動起來。進入到emulator所在目錄,執行emulator命令:

[plain] view plainprint?
01.$cd ~/software/android/android-sdk-linux/tools
02.$./emulator @AVD-2.3.3-V10 -partition-size 512
$cd ~/software/android/android-sdk-linux/tools
$./emulator @AVD-2.3.3-V10 -partition-size 512
AVD-2.3.3-V10表示你的模擬器名稱,與在Eclipse->AVDManager下的AVDName對應,-partition-size表示模擬器的存儲設備容量。

(2)接下來,我們需要把libJNITest.so文件拷貝到模擬器的/system/lib目錄下,執行以下命令:

[plain] view plainprint?
01.$cd ~/project/Android/JNITest/libs/armeabi/
02.$adb remount
03.$adb push libJNITest.so /system/lib
04.80 KB/s (10084 bytes in 0.121s)
$cd ~/project/Android/JNITest/libs/armeabi/
$adb remount
$adb push libJNITest.so /system/lib
80 KB/s (10084 bytes in 0.121s)

當在終端上看到有80 KB/s (10084 bytes in 0.121s)傳輸速度等信息的時候,說明拷貝成功。

(3)在終端上執行JNITest程序,這個我們可以在Eclipse下,右鍵點擊JNITest工程,RunAs->Android Application,即可在模擬器上啟動程序

2. 如何在Android中使用匯編語言

由於Android環境非常復雜,框架都是用Java,因此要使用C/C++都需要做很多配置,使用匯編的話需要做更多的工作。
我這邊使用的是最新的Android4.0的開發工具,NDK也是最新支持4.0的。這個NDK與老版本的有一些比較明顯的不同。
由於我用的是Mac OS X,因此配置起來比瘟抖死上的要容易許多,你不需要再裝些雜七雜八的第三方工具,直接可以使用你下載好的NDK。
首先,設置目標路徑——在你的Terminal中進入NDK的根目錄,隨後打NDK_PROJECT_PATH="<你要編譯的項目路徑>"。回車,再輸入export NDK_PROJECT_PATH
回車。
這里要注意的是NDK_PROJECT_PATH=後面的路徑需要加引號,否則無效。
由於NDK默認支持的默認編譯選項僅支持ARMv5到ARMv5TE架構,因此如果要使用比較高級的特性的話有兩種方法:
1、你有辦法將TARGET_ARCH_ABI的值變為armeabi-v7a,俺自己試了一下,木有成功。因此可以使用第二種方法,更簡單便捷:
2、在你的NDK目錄下,找到toolchains,然後找到arm-linux-androideabi-x.y.z目錄,在進去可以發現setup.mk文件。找到-march=armv7-a,將上面的神馬#ifdef都去掉,下面的#endif也都刪了。這樣就能確保編譯器使用ARMv7A來編譯。
完成上述操作之後我們就可以先用最簡單的方式來寫匯編了,即內聯匯編——

static int my_thumb(int mmy)
{
__asm__("movw r0, #1001 \t\n"
"movw r12, #2020 \t\n"
"add r0, r0, r12 \t\n"
"bx lr");

return mmy;
}

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
my_thumb(0);
return (*env)->NewStringUTF(env, "Hello from JNI !");
}


上述代碼其實就是基於NDK自帶的hello-jni項目修改的。最後用ndk-build可以成功編譯。

上面一段代碼是編譯器默認的使用Thumb/Thumb-2編譯的,因此我裡面寫的內聯匯編的指令都是Thumb代碼。
我們下面將講述一下如何使用ARM代碼並使用NEON指令集。
首先,在你的Android.mk中修改LOCAL_SRC_FILES,要將源文件名後面添加.neon後綴,比如LOCAL_SRC_FILES := hello-jni.c改成LOCAL_SRC_FILES := hello-jni.c.neon。
這里要注意的是你真正的源文件名不要修改,就修改LOCAL_SRC_FILES這個符號的值即可。
然後我們再添加新的變數,來指示ARM GCC使用ARM指令集來編譯——LOCAL_ARM_MODE := arm
這樣就OK了。我們修改一下代碼:

static int my_arm(int mmy)
{
__asm__("movw r0, #1001 \t\n"
"movw r12, #2020 \t\n"
"add r0, r0, r12 \t\n"
"vp.32 q0, r0 \t\n"
"bx lr");

return mmy;
}

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
my_arm(0);
return (*env)->NewStringUTF(env, "Hello from JNI !");
}


使用ndk-build後能正常通過編譯。
最後再上個最最高端的。直接寫匯編文件。NDK帶有GAS工具,因此按常理,完全可以寫匯編文件。一般匯編文件的後綴名為.s,因此我們創建一個xxx.s文件即可。
然後我這邊創建一個叫hey.s。在Android.mk中將這個文件添加上:LOCAL_SRC_FILES += hey.s.neon
我們這里看到,為了能在匯編文件中使用NEON指令集,我們在這里也把.neon後綴添加上。匯編器的makefile也認這個標識。
我們編輯hey.s文件:

.text
.align 4
.arm
.globl my_real_arm
my_real_arm:
add r0, r0, #256
vmov q0, q1
vp.32 q0, r0
bx lr
這里要注意的是,在Apple的匯編器中,函數名要加前綴下劃線,而NDK中提供的匯編器則不需要。
我們修改一下hello-jni.c,把這函數調進去:

extern void my_real_arm(int i);

static int my_arm(int mmy)
{
__asm__("movw r0, #1001 \t\n"
"movw r12, #2020 \t\n"
"add r0, r0, r12 \t\n"
"vp.32 q0, r0 \t\n"
"bx lr");

return mmy;
}
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
my_real_arm(0);
my_arm(0);
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
當然,我們為了確保編譯器能夠正確地將ARM和Thumb指令集做混合連接,我們可以在剛才的setup.mk中強制在TARGET_CFLAGS標志里加上-mthumb-interwork
在Windows操作系統中試驗,終於發現,只要將Application.mk中的APP_ABI中的標志,將armeabi去掉,僅留下armeabi-v7a就能順利使用neon了。這樣不需要修改setup.mk,也不需要將Sample中的那個標志判斷去掉,非常方便。
下面列一下可用的Android.mk編譯配置文件:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := HelloNeon
LOCAL_SRC_FILES := helloneon.c
LOCAL_ARM_MODE := arm
TARGET_CFLAGS += -mthumb-interwork
TARGET_CFLAGS += -std=gnu11
TARGET_CFLAGS += -O3
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS := -DHAVE_NEON=1
LOCAL_SRC_FILES += neontest.s.neon
LOCAL_ARM_NEON := true
endif
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
$(call import-mole,cpufeatures)
在使用JNI時,只需要在你當前項目工程目錄中添加jni文件夾,然後在裡面根據Sample中所提供的文件布局來做即可。當你用ndk-build(Windows下要在cygwin控制台中用ndk-build.cmd)來編譯時, 如果構建成功,則會在libs文件夾內生成一個libXXX.so。然後用Eclipse ADT重新打開你的項目工程,就會發現jni文件目錄以及生成好的so文件都會在你的工程文件目錄中展現出來。當然,你後面也能直接在Eclipse IDE下編輯.s匯編文件,這樣就更容易閱讀了。
最後,在Android匯編器中如果要注釋某條語句,那麼必須使用C89/90中的注釋符——/* ... */
用分號以及後來C++98中所引入的//形式都不管用。
在最新的NDK版本android-ndk-r8d中加入了ARM-Linux GCC4.7以及當前大紅大紫的LLVM Clang3.1。不過由於LLVM Clang3.1的很多編譯選項與GCC有不少區別,因此在使用Clang3.1的時候需要自己去配置相應的編譯選項。這個版本的NDK默認的編譯器工具鏈使用的是GCC4.6版本。如果要使用GCC4.7,那麼可以在Application.mk文件中添加NDK_TOOLCHAIN_VERSION=4.7;如果要使用Clang3.1,那麼可以在Application.mk中添加NDK_TOOLCHAIN_VERSION=clang3.1。下面給出一個合法的Application.mk的內容:

# Build with LLVM Clang3.1
#NDK_TOOLCHAIN_VERSION=clang3.1

# Build with ARM-Linux GCC4.7
NDK_TOOLCHAIN_VERSION=4.7

# Build only ARMv7-A machine code.
APP_ABI := armeabi-v7a

以上參考豆丁網
南京寶雲安卓培訓課程火熱報名中~

3. AndroidStudio如何配置NDK/JNIAndroidStudio怎麼調用so動態鏈接庫

AndroidStudio怎麼調用so動態鏈接庫?在我們日常開發中,經常會用到一些復雜的加密演算法以保證通信的安全。通常這些演算法會用C或C++實現後打包成.so動態鏈接庫並向Java層開發介面方便調用。


以AndroidStudio為例

1 . 首先去下載NDK包,下載路徑如下可根據自己系統定點下載

https://developer.android.google.cn/ndk/downloads/index.html

static{
System.loadLibrary("jnitext");
}
publicnativeStringget_1111CLang_1String();

4. android ndk 開發,C++ 調用Java的方法

  1. Android.mk文件:



LOCAL_SRC_FILES參數用空格隔開

[c-sharp]view plainprint?

LOCAL_PATH:=$(callmy-dir)

include$(CLEAR_VARS)

LOCAL_MODULE:=native

LOCAL_SRC_FILES:=geolo.cppmy_jni.h

include$(BUILD_SHARED_LIBRARY)


2. geolo.cpp

先用FindClass方法找到java類,有點類似java的反射用LoadClass

再用CallObjectMethod方法調用Java類的函數。


[c-sharp]view plainprint?

#include"my_jni.h"

jobjectgetInstance(JNIEnv*env,jclassobj_class){

jmethodIDconstruction_id=env->GetMethodID(obj_class,"<init>","()V");

jobjectobj=env->NewObject(obj_class,construction_id);

returnobj;

}

JNIEXPORTjstringJNICALLJava_com_easepal_geolo_CActivityMain_stringFromJNI(JNIEnv*env,jobjectthiz){

jstringstr;

jclassjava_class=env->FindClass("com/easepal/geolo/CForCall");

if(java_class==0){

returnenv->NewStringUTF("notfindclass!");

}

jobjectjava_obj=getInstance(env,java_class);

if(java_obj==0){

returnenv->NewStringUTF("notfindjavaOBJ!");

}

jmethodIDjava_method=env->GetMethodID(java_class,"GetJavaString","()Ljava/lang/String;");

if(java_method==0){

returnenv->NewStringUTF("notfindjavamethod!");

}

str=(jstring)env->CallObjectMethod(java_obj,java_method);

returnstr;

}

3. my_jni.h


[c-sharp]view plainprint?

/*DONOTEDITTHISFILE-itismachinegenerated*/

#include<jni.h>

/*Headerforclasscom_easepal_geolo_CActivityMain*/

#ifndef_Included_com_easepal_geolo_CActivityMain

#define_Included_com_easepal_geolo_CActivityMain

#ifdef__cplusplus

extern"C"{

#endif

/*

*Class:com_easepal_geolo_CActivityMain

*Method:stringFromJNI

*Signature:()Ljava/lang/String;

*/

JNIEXPORTjstringJNICALLJava_com_easepal_geolo_CActivityMain_stringFromJNI(JNIEnv*,jobject);

#ifdef__cplusplus

}

#endif

#endif


4.CActivityMain.java


[c-sharp]view plainprint?

packagecom.easepal.geolo;

importandroid.app.Activity;

importandroid.os.Bundle;

importandroid.widget.TextView;

{

/**.*/

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

TextViewtv=newTextView(this);

tv.setText(stringFromJNI("hello"));

setContentView(tv);

}

static{

System.loadLibrary("native");

}

(Stringstr);

}


5.CForCall.java


[c-sharp]view plainprint?

packagecom.easepal.geolo;

publicclassCForCall{

publicCForCall(){};

//public~CForCall(){};

publicStringGetJavaString(){

Stringstr;

str="123456";

returnstr;

}

}

熱點內容
促銷演算法模型 發布:2025-03-16 16:56:55 瀏覽:92
線程非同步java 發布:2025-03-16 16:51:52 瀏覽:258
軟體編程有哪些 發布:2025-03-16 16:46:07 瀏覽:479
最近上傳91 發布:2025-03-16 16:46:03 瀏覽:703
珍珠台編程 發布:2025-03-16 16:40:25 瀏覽:899
伺服器如何連接寬頻 發布:2025-03-16 16:31:19 瀏覽:657
電腦硬體消息查詢腳本 發布:2025-03-16 16:22:39 瀏覽:867
寶馬五系降價取消了哪些配置 發布:2025-03-16 16:09:41 瀏覽:240
學班java 發布:2025-03-16 16:09:00 瀏覽:599
切金磚解壓 發布:2025-03-16 16:08:45 瀏覽:774