I am currently developing an app for Android and IOS using Qt Quick Controls 2 which will have login possibility. The account credentials will be stored into an external SQL database. I have figured out how I can interact with the database, but I am not able to figure out how I can use sessions in Qt for Android and IOS such that the user do not need to type the login credentials each time.
One possible way could be to store the credentials to a file locally on the phone, and then access the file each time the app is started. However, I am not sure if this is the best and safest way.
Thanks.
QSettings class is used for state management. QSettings information is often stored in the system registry on Windows, and in property list files on macOS and iOS. Here is raw example code that uses QSettings to store/retrieve session parameters .. you can extend to include needed session login management scenarios:
main.cpp
int main( int argc, char ** argv ) {
QApplication app( argc, argv );
app.setOrganizationName("myOrg");
app.setOrganizationDomain("myOrg.net");
app.setApplicationName("qsettings-test");
MyMainWindow mw;
mw.show();
return app.exec();
}
Then in your source .cpp
void MyMainWindow::readSettings() {
QSettings settings;
QString user = settings.value("UserName");
int lifTime = settings.value("sessionLifeTime").toInt();;
QByteArray state = settings.value("state", QByteArray())
.toByteArray();
restoreState(state);
}
// ...... lots of your code
void MyMainWindow::closeEvent(QCloseEvent* event) {
if (maybeSave()) {
writeSettings();
event->accept();
} else {
event->ignore();
}
}
void MyMainWindow::writeSettings() {
/* Save postion/size of main window */
QSettings settings;
settings.setValue("sessionLifeTime", 7);
settings.setValue("UserName", user);
settings.setValue("state", saveState());
}
You can also access INI and PLIST configuration files with QSettings class, For Android this can be considered where your INI file must be copied during build (store in res folder and include it in .pro ).
Related
I'm trying to load a external library for certain app when it be launched (on Platform Android 12).
And the external library will hook some function in it initialize function and then can help me get app's info.
The point is ,i can't load my library correctly.
I know Android 8+ dont allow load system lib by app,and dlopen will do return address check as blow
__attribute__((__weak__))
void* dlopen(const char* filename, int flag) {
const void* caller_addr = __builtin_return_address(0);
return __loader_dlopen(filename, flag, caller_addr);
}
You should make the caller_addr be a system lib address(or some like this?).
So,I used PLT hook tools to hook __loader_dlopen() in libdl.so,and do external load for target app like this to pass validation.
void* my_fake__loader_dlopen(const char* filename,int flag,void* caller_addr)
{
if(in_target_app)
{
void* res = __loader_dlopen(target_so_path,flag,caller_addr)//res always return NULL
}
return __loader_dlopen(filename,flag,caller_addr);
}
But res always return NULL,i cant load my lib correctly.
which of the above steps went wrong ? or is there another way to achieve my goal?
PS:
I can make sure:
put my lib in /system/lib64/
hook function correctly
I saw a post on bypassing the root detection for android app by using frida server. When i following these steps, root detection is not working. Any one have an idea to protect the root detection from bypassing using Frida server/any other
Check for root in a shared library and launch an activity saying, the device is rooted from the shared lib itself clearing the back stack.
The native binaries are difficult to reverse engineer (They need function name to manipulate on Frida).
Also you can prevent frida from attaching to your app.
From frida docs we can see that frida uses ptrace
Frida needs in a first step to inject an agent in the targeted >application so that it is in the memory space of the process.
On Android and Linux such injection is done with ptrace by attaching
or spawning a process and then injecting the agent. Once the agent is
injected, it communicates with its server through a pipe.
When the ptrace system call is used to attach to a process, the "TracerPid" field in the status file of the debugged process shows the PID of the attaching process. The default value of "TracerPid" is 0 (no process attached). Consequently, finding anything other than 0 in that field is a sign of debugging or other ptrace shenanigans.
The following implementation is from Tim Strazzere's Anti-Emulator project:
#include <jni.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <pthread.h>
static int child_pid;
void *monitor_pid() {
int status;
waitpid(child_pid, &status, 0);
/* Child status should never change. */
_exit(0); // Commit seppuku
}
void anti_debug() {
child_pid = fork();
if (child_pid == 0)
{
int ppid = getppid();
int status;
if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) == 0)
{
waitpid(ppid, &status, 0);
ptrace(PTRACE_CONT, ppid, NULL, NULL);
while (waitpid(ppid, &status, 0)) {
if (WIFSTOPPED(status)) {
ptrace(PTRACE_CONT, ppid, NULL, NULL);
} else {
// Process has exited
_exit(0);
}
}
}
} else {
pthread_t t;
/* Start the monitoring thread */
pthread_create(&t, NULL, monitor_pid, (void *)NULL);
}
}
JNIEXPORT void JNICALL
Java_sg_vantagepoint_antidebug_MainActivity_antidebug(JNIEnv *env, jobject instance) {
anti_debug();
}
Please refer to this guide for anti-debugging tricks by vantagepoint.
There is a specific section in this guide which addresses frida
Also https://github.com/b-mueller/frida-detection-demo
Otherwise, you can use the service of Appdome (IPaaS) to block frida from attaching to your app
I am trying to exchange files between a .Net Desktop App and a Xamarin.Forms Android app. I really had trouble getting resources and help, so I want this question to also wrap some stuff up - for other interested users (not only of Xamarin Forms)
So far I got to read files and folders in .Net C# using
Christophe Geers' Blog and Fun with MTP and because writing did not work on all of my devices Windows File Stuff by Flauschig
On Xamarin.Forms side of the wall I first stumbled over Xamarin doc and A lib to store from pcl code and also Plugin.Permissions.
With all these sources above I was able to get reading and writing on the Android (Samsung A5, Android 6.0) to work.
With this description on filestructure I thought the following Code will always get a valid path:
public string GetExternalFolder()
{
GetPermission();
var externalFolder = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, "Android", "data", "com.exampledom.appname", "files");
if (!Directory.Exists(externalFolder))
CreateFolderStructure();
return externalFolder;
}
GetPermission() is taken from Plugin.Permissions and will throw exception if permission is not given.
CreateFolderStructure() is using pcl.storage - and looks like this.
private async void CreateFolderStructure()
{
try
{
IFolder rootFolder = await FileSystem.Current.GetFolderFromPathAsync(Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path));
var subpaths = new[] {"Android", "data", "com.exampledom.appname", "files"};
foreach (var dir in subpaths)
{
if (!string.IsNullOrEmpty(dir))
rootFolder = await rootFolder.CreateFolderAsync(dir, CreationCollisionOption.OpenIfExists);
}
Log("Folder structure created!");
}
catch (Exception e)
{
Log("Folder structure cannot be created!");
Console.WriteLine("Failed to log! " + e.Message);
}
}
Ok, now for the question:
The Folder that is created by this Method is only created on one device I tested on (proof of concept) - all others (eg Samsung A3, Android 6.0) nothing happens(proof of helpless developer). A reboot is not the solution.
Also on the device this works on - the permission is requested as expected. There is no permission request on the other devices.
Why is the desired folder not created during install? It seems all other apps do have such a folder 'Android/data/com.exampledom.appname/files'.
What am I missing? It seems overly hard to import/export to android.
#smack Does CreationCollisionOptions.OpenIfExists really create a folder? I don't think so. Is there not CreateIfNotExists enum?
I'm developing Phonegap application (using AngularJs+Bootstrap) which supports iOS and Android. We had to maintain two code bases so far but its the same functionalities, only few differences like below.
Application name/icons are different
Main url is different for web-service calls
Ex :
PhoneGap App X : call http://abc/xappinfo weservice, use x_icon_app.png
(This has to build for both iOS and Android which i have no issue)
PhoneGap App Y : call http://xyz/yappinfo weservice, use y_icon_app.png and other UI elements for mobile skin
(This also has to build for both iOS and Android)
Both PhoneGap App X and Y uses same code for business logics.
I would like to maintain one code base for both apps since there only few differences. Is there any way I could achieve this or simplify my development effort?
I had a similar situation. I placed all my app folders in a single folder and placed the following code in a file in the root folder called: persist.js. Its purpose is to persist file changes across all of the different apps keeping the same path. It is a little manual, but works...
var fs = require('fs');
var chalk = require('chalk');
var argv = require('minimist')(process.argv.slice(2));
var file = argv.f;
var apps = [
'app_folder_1',
'app_folder_2',
'app_folder_3',
'app_folder_4',
'app_folder_5',
];
if(file){
if (fs.existsSync(file)) {
console.log(chalk.blue('Found source file'));
var fileWithoutApp = file.substring(file.indexOf('/'));
apps.map(app => {
fs.writeFileSync(app + fileWithoutApp, fs.readFileSync(file));
console.log(chalk.green(`File copied to: ${app + fileWithoutApp}`))
});
} else {
console.log(chalk.red('File does not exist'));
}
} else {
console.log(chalk.red('No file specified'));
}
After changes are made to a file within any of the project folders just call the following from the command line:
node persist -f [relative path to your file that has changes]
This will persist the change across all projects. Like I said, a little manual... but effective :)
When u use cordova or ionic + angularjs you can compile application for both device this is more simple you like complication !!
I want to save some user credentials in my qt application that runs on Android.
I use QSettings for this like so:
QString appPath = QCoreApplication::applicationDirPath()+QLatin1Char('/');
set = new QSettings(appPath+"test",
QSettings::NativeFormat);
set->setValue ( "user/username", "NameOfTheUser" );
set->setValue ( "user/password", "UserPassword" );
set->sync();
I restart the app and inside an initialize() method I have:
QString username(set->value("user/username",
( QVariant ) tr ( "defaultUser" ) ).toString());
QString password(set->value("user/password",
( QVariant ) tr ( "defaultPass" ) ).toString());
The username and password vars are not read from the QSettings.
The same code is working on Windows.
Thank you
I also ran into similar problem and found out that 2 things should be done:
path to settings file should be specified
QSettings::sync() should be explicitly called after every settings change.
So on Windows I had this working:
QSettings settings("settings.ini", QSettings::IniFormat);
settings.setValue(GRID_ENABLED, enabled);
On Android I have to use the following code:
QSettings settings("/sdcard/settings.ini", QSettings::NativeFormat); //can be IniFormat, no difference
settings.setValue(GRID_ENABLED, enabled);
settings.sync();
Probably using "sdcard" is not good enough and you should use other directory.
You can try to specify the location of the setting file to a writable location which exists even if the application is removed :
#include <QSettings>
#include <QStandardPaths>
QString path ;
QString filename;
path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) ;
filename = “config.ini” ;
QSettings settings(path + “/”+ filename,QSettings::IniFormat) ;
Here QStandardPaths::GenericDataLocation returns a directory location where persistent data shared across applications can be stored and it is never empty.
Also you can set the application and organization name in the main of your application once :
qApp->setOrganizationName("Company");
qApp->setApplicationName("App");
As noted, a re-deploy of the application from Qt Creator wipes the settings.
This is still true in Qt Creator 3.3.2 with the following caveat. When you deploy the app on Android and look at the Application Output window, there is a tool bar with a "stop" button (red square) and a "Re-run this run configuration" button (green triangle).
The initial deploy from Qt starts the app. The QSettings object is cleared or empty. Any changes to the QSettings object will be saved in the object.
If you stop the app with the red button, then immediately restart the app with the green Re-run button, the app will restart and all changes to the QSettings object in the previous run will still be there.
I assume this emulates the start, exit, restart of the app on a device.
Hi I've found the solution, tested on 3 different Android device. You can set the following path for your settings.
mPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
QString filename = "se.ini";
mPath = mPath + "/" + filename;
By following code you save your info under above location.
void ProfileManager::saveToRegistery()
{
QSettings settings(mPath , QSettings::NativeFormat);
settings.setValue("SE/Mail" , mMail);
settings.setValue("SE/Pass" , mPass);
settings.sync();
}
If you have any trouble with saving that place, you ask user permission for accessing any file with:
bool QAndroidPermissions::requestPermissions()
{
QtAndroid::PermissionResult r =
QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE");
if(r == QtAndroid::PermissionResult::Denied) {
QtAndroid::requestPermissionsSync( QStringList() <<
"android.permission.WRITE_EXTERNAL_STORAGE" );
r =QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE");
if(r == QtAndroid::PermissionResult::Denied) {
return false;
}
}
return true;
}
Hope this helps,
I had a problem similar to the above, and it turned out that everything worked just fine. That is it did work with a simple QSettings object without any arguments.
HOWEVER, every time I re-deployed the application from Qt Creator, the settings file was destroyed, leading me to the conclusion that QSettings did not work.
The problem should, according to Bogdan himself, have been fixed in Qt Creator 3.2
The only problem with your code is that for Android you have to use QStandartPaths to get path and not the QCoreApplication::applicationDirPath().
QCoreApplication::applicationDirPath() will give you the windows application path to your Android Application, which won't work on Android.