#!/bin/bash
path_current=`pwd`
path_script=$(cd "$(dirname "$0")"; pwd)
DEFAULT_PATH=$PATH
ANDROID_NDK_HOME=~/Android/Sdk/ndk/20.1.5948944
declare -A qt_architectures=( ["x86_64"]="x86_64" ["x86"]="x86" ["arm64"]="arm64-v8a" ["arm"]="armeabi-v7a" )
rm -rf android
if [ ! -d "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin" ]; then
echo "failed to find linux-x86_64 home. please install ndk-r20+ version in ubuntu-18.04 system"
exit 1
fi
ANDROID_TOOLCHAIN="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin"
for arch in ${!qt_architectures[@]}
do
case $arch in
arm)
ANDROID_API=16
;;
x86)
ANDROID_API=16
;;
arm64)
ANDROID_API=21
;;
x86_64)
ANDROID_API=21
;;
esac
rm -rf ${path_script}/build
ANDROID_DEFINITION="-DCMAKE_FIND_ROOT_PATH:PATH=${path_script}/../openssl/android/${arch};${path_script}/../zlib/android/${arch}"
ANDROID_DEFINITION="${ANDROID_DEFINITION} -DWITH_EXAMPLES=OFF"
ANDROID_DEFINITION="${ANDROID_DEFINITION} -DCMAKE_BUILD_TYPE:STRING=Release"
ANDROID_DEFINITION="${ANDROID_DEFINITION} -DANDROID_ABI:STRING=${qt_architectures[$arch]}"
ANDROID_DEFINITION="${ANDROID_DEFINITION} -DANDROID_NATIVE_API_LEVEL:STRING=${ANDROID_API}"
ANDROID_DEFINITION="${ANDROID_DEFINITION} -DANDROID_NDK:PATH=${ANDROID_NDK_HOME}"
ANDROID_DEFINITION="${ANDROID_DEFINITION} -DCMAKE_CXX_COMPILER:STRING=${ANDROID_TOOLCHAIN}/clang++"
ANDROID_DEFINITION="${ANDROID_DEFINITION} -DCMAKE_C_COMPILER:STRING=${ANDROID_TOOLCHAIN}/clang"
ANDROID_DEFINITION="${ANDROID_DEFINITION} -DCMAKE_TOOLCHAIN_FILE:PATH=${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake"
mkdir -p ${path_script}/build && cd ${path_script}/build && cmake -DCMAKE_C_FLAGS="-fPIC -Wall" -DCMAKE_INSTALL_PREFIX=${path_script}/android/${arch} ${ANDROID_DEFINITION} ../libssh-0.9.3
make clean && make && make install
done
分类目录归档:Qt开发
Qt的CMakefiles样本1
cmake_minimum_required(VERSION 3.1)
project(untitled3 LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS core widgets REQUIRED)
add_executable(${PROJECT_NAME} "main.cpp" "qml.qrc")
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Widgets)
##特别注意是Qt5而不是Qt
使用匿名函数,简易地把同步转异步
使用匿名函数,简易地把同步转异步。
大概思路,已经省去了线程池的相关说明。
#define MYASSERT(x)
typedef std::function FunAsyncTask;
typedef std::function FunSuccessCallBack;
typedef std::function FunErrorCallBack;
//从KAsyncTask派生
class AsyncTask
{
private:
const FunAsyncTask task;
const FunSuccessCallBack ok_cb;
const FunErrorCallBack err_cb;
const QPointer callerThiz; //外部调用者的This指针,目的利用它来检验当前匿名函数所捕获的参数是否仍有效。
QVariant result;
QVariant err;
//ToDo保存调用线程,调用线程与成功及错误的处理是同一个线程,也即是调用成功及错误之前先检查线程是否相同。
int threadCallId; //任务请求的线程。
int threadDoTaskId; //任务处理的线程
public:
static void post_aync_task(QObject *thiz, FunAsyncTask t, FunSuccessCallBack ok, FunErrorCallBack err)
{
AsyncTask *task = new AsyncTask(thiz, t, ok, err);
//ToDo推送至多线程任务队列。
}
private:
AsyncTask(QObject *thiz, FunAsyncTask t, FunSuccessCallBack ok, FunErrorCallBack err)
: callerThiz(thiz), task(t), ok_cb(ok), err_cb(err)
{
threadCallId = GetCurrentThreadId();
}
void run()
{
// AnyncThread do the job.
threadDoTaskId = GetCurrentThreadId();
try
{
result = task();
//ToDo Save Ok
}
catch (...)
{
//TODO Save Error;
}
}
void handleResult()
{
//ToDo MainThread to do the job.
MYASSERT(callerThiz);
MYASSERT(threadCallId == GetCurrentThreadId());
ok_cb(result);
}
void handleError()
{
//ToDo MainThread to do the Error
MYASSERT(callerThiz);
MYASSERT(threadCallId == GetCurrentThreadId());
err_cb(err);
}
};
void assertValidTaskLambda(char* txt)
{
//ToDo提取lamda表达式的中括号的参数进行检查,不允许使用"=&"的特殊字符,有该字符则输出错误及抛出异常。
//提取括号外及大括号前的字符串,不允许"mutable"参数使用。
printf("\r\n%s", txt);
}
void assertValidCallBackLambda(char* ok, char* err)
{
//ToDo提取lamda表达式的中括号的参数进行检查,不允许使用"&"的特殊字符,有该字符则输出错误及抛出异常。
//提取括号外及大括号前的字符串,不允许"mutable"参数使用。
printf("\r\n%s-%s", ok, err);
}
#define POST_AYNC_TASK(task, ok_cb, err_cb) \
{\
assertValidQObject(this); \
assertValidTaskLambda(#task); \
assertValidCallBackLambda(#ok_cb, #err_cb) \
AsyncTask::post_aync_task(this, task, ok_cb, err_cb); \
}
int MyClass::execute()
{
int x = 1;
int y = 2;
int z = 3;
int m = 4;
FunAsyncTask task = [x, y, z]()->int{
return QVariant(123);
};
FunSuccessCallBack ok = [x, m](QVariant r){
printf("ok...ok...%d", r);
};
FunErrorCallBack err = [z, m](QVariant err){
printf("failed...failed...%d", err);
};
POST_AYNC_TASK(task, ok, err); //这种使用,报错。
// 推荐以下方式使用,目的是语法检查,减少多线程出错。
// POST_AYNC_TASK((task_exp),(ok_exp),(err_exp))
// 如果表达式不用括号包裹起来的话,可能会导致编译出错。
POST_AYNC_TASK(([x, y, z]()->QVariant{
int v1 = x;
int v2 = v1*2;
Sleep(1000);
return QVariant(v2 + z);
}), ([=](QVariant r){
printf("ok...ok...%d", r);
}), ([=](QVariant err){
printf("failed...failed...%d", err);
}));
getchar();
}
cef的Qt的封装库及webrtc的测试
1.webrtc已经在cef3.x中支持。
2.由于cef的编译复杂性,有一些第三方机构专门编译一些全功能的二进制库,并提供了相应的例子,很方便地直接引入到第三方应用中。
3.在window中,简述其编译测试如下:
A-首先下载cef的库文件。下载地址如下:
http://opensource.spotify.com/cefbuilds/index.html【记住要下载32位的版本,不要下载64位的】
下载完成,先阅读其CMakeLists.txt文件,它说明了在各个平台该如何二次编译,如window的编译截图如下:
注:————–一定要用cmake -G “Visual Studio 14″【也即是vs2015,社区版就可以了编译了】的命令,令其生成工程vc的工程文件。———
注:————–不要用cmake的gui方式生成工程,因为可能会失败,而产生困扰——————————-
4.用vs2015打开工程,选择全编译。
5.调试cefclient工程,在调试器中添加–enable-media-stream选项。
6.打开webrtc的测试页面如下:
https://webrtc.github.io/samples/
7.截图如下:经验检,摄像头及声音都正常。
8.
—————————–
有人针对这场景写了一个QT的封装库,可以方便直接被Qt使用,在github随便搜索的结果有如下,可以逐个测试。
https://tishion.github.io/QCefView/
—————————
https://github.com/GreatTux/CefMinGWQt,这个是mingw版本。
———————————–
https://github.com/Dax89/QtCEF
——————-
Android后台运行
在播放音乐或定时器的情况,需要程序在后台运行,则此时可以打开以下开关。
<meta-data android:name=”android.app.background_running” android:value=”true”/>
QML自定义属性集合
Page{
property
variant
musicList: []自定义数组
property variant myjson:{} 自定义JSON集合
signal abc(variant musicList);
function efg(v){
}
}
QML的多语言支持
1.Pro工程文件配置
TRANSLATIONS
+=
muyu.ts
lupdate_only{
SOURCES
+=
\
kxmob/*.qml
\
listmgr/*.qml
}
2.导入语言包
QTranslator
translator;
if(translator.load(“:/muyu.qm”)){
app.installTranslator(&translator);
}
3.
工具->外部->Qt语言家->更新翻译lupdate,lrelease。
QML控件风格与应用配置的读与写
QML quickcontrol已经具备设置风格,故需要如下设置(可参考Qt5.6.0\Examples\Qt-5.6\qtquickcontrols2\controls例子)
在QML中导入风格库
import
Qt.labs.controls
1.0
import
Qt.labs.controls.material
1.0
import
Qt.labs.controls.universal
1.0
Qt闪屏
Qt的闪屏,使用QtCreator向导创建的Android应用,在应用启动时,首先看到黑色的背景及标题,非常丑,一直想修改它。偶然看到一个大作的应用,非常优雅的实现一个闪屏,完美的解决了原有默认的启动效果,于是学习他制作了一个例子。
例子仓库:https://github.com/kxtry/AndroidSplash
-
首先是创建AndroidManifest.xml文件
-
修改该文件里的几项如下图:
文件目录结构如下:
Apptheme.xml文件内容:
<?xml version=”1.0″ encoding=”utf-8″?>
<resources>
<style name=”AppTheme” parent=”@android:style/Theme.DeviceDefault.Light.NoActionBar”>
<item name=”android:windowBackground”>@drawable/splash</item>
</style>
</resources>
Splash.xml文件内容如下:
<?xml version=”1.0″ encoding=”utf-8″?>
<layer-list xmlns:android=”http://schemas.android.com/apk/res/android”>
<item>
<shape android:shape=”rectangle” >
<solid android:color=”#FFFFFFFF”/>
</shape>
</item>
<item>
<bitmap android:src=”@drawable/icon” android:gravity=”center” />
</item>
</layer-list>
- 编译程序,即可。
QTDesigner的QVBoxLayout自动随窗口拉伸
在MainWindow的构造函数中添加如下代码:
//设置Ui
ui.setupUi(this);
//使Ui可自适应父窗口大小
QVBoxLayout* mainLayout = new QVBoxLayout;
mainLayout->addWidget(ui.verticalLayoutWidget);
setLayout(mainLayout);
或
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QVBoxLayout* mainLayout = new QVBoxLayout;
mainLayout->addWidget(ui->verticalLayoutWidget);
ui->centralWidget->setLayout(mainLayout);
}