Commit 382e0142 authored by Paul Cartier's avatar Paul Cartier

Create bctoolbox-ios dynamic framework to handle UIApplication

Framework dynamically loaded in iOS application to handle UIApplication unavailability in app extension
parent 25f4a51e
......@@ -47,6 +47,8 @@ option(ENABLE_STRICT "Pass strict flags to the compiler" ON)
option(ENABLE_TESTS_COMPONENT "Enable compilation of tests helper library" ON)
option(ENABLE_TESTS "Enable compilation of tests" ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS NO)
include(CheckLibraryExists)
include(CheckSymbolExists)
......
......@@ -35,6 +35,10 @@ set(HEADER_FILES
vfs.h
)
if(APPLE)
list(APPEND HEADER_FILES ios_utils.hh)
endif()
if(MBEDTLS_FOUND OR POLARSSL_FOUND)
list(APPEND HEADER_FILES crypto.h)
endif()
......
/*
* Copyright (c) 2010-2019 Belledonne Communications SARL.
*
* This file is part of Liblinphone.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <memory>
#include <functional>
namespace bctoolbox {
class IOSUtilsInterface {
public:
virtual unsigned long beginBackgroundTask(const char *name, std::function<void()> cb) = 0;
virtual void endBackgroundTask(unsigned long id) = 0;
virtual bool isApplicationStateActive() = 0;
virtual ~IOSUtilsInterface() = default;
};
class IOSUtils {
public:
unsigned long beginBackgroundTask(const char *name, std::function<void()> cb);
void endBackgroundTask(unsigned long id);
bool isApplicationStateActive();
static IOSUtils& getUtils();
IOSUtils(const IOSUtils&) = delete;
IOSUtils& operator=(const IOSUtils&) = delete;
~IOSUtils();
private:
void *mHandle;
IOSUtilsInterface *mUtils;
static std::unique_ptr<IOSUtils> sInstance;
IOSUtils();
bool isApp();
void openDynamicLib();
void *loadSymbol(const char *symbol);
};
} //namespace bctoolbox
......@@ -36,6 +36,15 @@ set(BCTOOLBOX_CXX_SOURCE_FILES
utils/regex.cc
)
if(APPLE)
set(BCTOOLBOX_OBJC_SOURCE_FILES
utils/ios_utils.mm
)
set(BCTOOLBOX_IOS_OBJC_SOURCE_FILES
utils/ios_utils_app.mm
)
endif()
if(ANDROID)
list(APPEND BCTOOLBOX_CXX_SOURCE_FILES conversion/charconv_android.cc)
elseif(WIN32)
......@@ -65,12 +74,15 @@ if(ENABLE_TESTS_COMPONENT)
set(BCTOOLBOX_C_TESTER_SOURCE_FILES tester.c)
endif()
set(BCTOOLBOX_SOURCE_FILES ${BCTOOLBOX_C_SOURCE_FILES} ${BCTOOLBOX_CXX_SOURCE_FILES})
set(BCTOOLBOX_SOURCE_FILES ${BCTOOLBOX_C_SOURCE_FILES} ${BCTOOLBOX_CXX_SOURCE_FILES} ${BCTOOLBOX_OBJC_SOURCE_FILES})
set(BCTOOLBOX_IOS_SOURCE_FILES ${BCTOOLBOX_IOS_OBJC_SOURCE_FILES})
set(BCTOOLBOX_TESTER_SOURCE_FILES ${BCTOOLBOX_C_TESTER_SOURCE_FILES})
bc_apply_compile_flags(BCTOOLBOX_C_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C)
bc_apply_compile_flags(BCTOOLBOX_C_TESTER_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C)
bc_apply_compile_flags(BCTOOLBOX_CXX_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX)
bc_apply_compile_flags(BCTOOLBOX_OBJC_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC)
bc_apply_compile_flags(BCTOOLBOX_IOS_OBJC_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC)
if(ENABLE_STATIC)
add_library(bctoolbox-static STATIC ${BCTOOLBOX_SOURCE_FILES} ${BCTOOLBOX_HEADER_FILES})
......@@ -191,6 +203,19 @@ if(ENABLE_SHARED)
)
endif()
if(APPLE)
if(IOS)
add_library(bctoolbox-ios SHARED ${BCTOOLBOX_IOS_SOURCE_FILES})
target_link_libraries(bctoolbox-ios PRIVATE bctoolbox)
set_target_properties(bctoolbox-ios PROPERTIES
FRAMEWORK TRUE
MACOSX_FRAMEWORK_IDENTIFIER org.linphone.bctoolbox-ios
MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/build/osx/Info.plist.in"
LINK_FLAGS "-framework UIKit -framework Foundation -framework CoreFoundation"
)
endif()
endif()
if(MBEDTLS_FOUND)
if(ENABLE_STATIC)
target_include_directories(bctoolbox-static SYSTEM PRIVATE ${MBEDTLS_INCLUDE_DIRS})
......@@ -274,6 +299,19 @@ if(ENABLE_SHARED)
endif()
endif()
if(APPLE)
if(IOS)
install(TARGETS bctoolbox-ios EXPORT ${EXPORT_TARGETS_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
FRAMEWORK DESTINATION Frameworks
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
COMPONENT core
)
endif()
endif()
if(MSVC)
# Disable "was deprecated" warnings of windows compiler (typically using strcpy_s instead of strcpy and stupid things like this).
if(ENABLE_SHARED)
......
/*
* Copyright (c) 2010-2019 Belledonne Communications SARL.
*
* This file is part of Liblinphone.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef __APPLE__
#import <Foundation/Foundation.h>
#include <dlfcn.h>
#include "bctoolbox/ios_utils.hh"
#include "bctoolbox/exception.hh"
#include "bctoolbox/logging.h"
#include "ios_utils_stub.hh"
namespace bctoolbox {
std::unique_ptr<IOSUtils> IOSUtils::sInstance = nullptr;
IOSUtils& IOSUtils::getUtils() {
if (!sInstance) {
sInstance = std::unique_ptr<IOSUtils>(new IOSUtils);
}
return *sInstance;
}
IOSUtils::IOSUtils() {
if (isApp()) {
openDynamicLib();
using create_t = IOSUtilsInterface *(*)();
auto createUtils = reinterpret_cast<create_t>(loadSymbol("bctbx_create_ios_utils_app"));
mUtils = createUtils();
} else {
mUtils = new IOSUtilsStub();
}
}
IOSUtils::~IOSUtils() {
if (isApp()) {
using destroy_t = void (*)(IOSUtilsInterface *);
auto destroyUtils = reinterpret_cast<destroy_t>(loadSymbol("bctbx_destroy_ios_utils_app"));
destroyUtils(mUtils);
dlclose(mHandle);
} else {
delete mUtils;
}
}
bool IOSUtils::isApp() {
return [[[NSBundle mainBundle] bundlePath] hasSuffix:@".app"];
}
void IOSUtils::openDynamicLib() {
NSString *frameworkPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString: @"/Frameworks/bctoolbox-ios.framework/bctoolbox-ios"];
const char *frameworkChar = [frameworkPath cStringUsingEncoding:[NSString defaultCStringEncoding]];
mHandle = dlopen(frameworkChar, RTLD_LAZY);
if (!mHandle) {
throw BCTBX_EXCEPTION << "bctoolbox error dlopen : " << dlerror();
}
// reset errors
dlerror();
}
void *IOSUtils::loadSymbol(const char *symbol) {
void *loadedSymbol = dlsym(mHandle, symbol);
const char *dlsym_error = dlerror();
if (dlsym_error) {
std::string error = dlsym_error;
dlclose(mHandle);
throw BCTBX_EXCEPTION << "bctoolbox error dlsym : " << error;
}
return loadedSymbol;
}
unsigned long IOSUtils::beginBackgroundTask(const char *name, std::function<void()> cb) {
return mUtils->beginBackgroundTask(name, cb);
}
void IOSUtils::endBackgroundTask(unsigned long id) {
return mUtils->endBackgroundTask(id);
}
bool IOSUtils::isApplicationStateActive() {
return mUtils->isApplicationStateActive();
}
unsigned long IOSUtilsStub::beginBackgroundTask(const char *name, std::function<void()> cb) {
return 0;
}
void IOSUtilsStub::endBackgroundTask(unsigned long id) {}
bool IOSUtilsStub::isApplicationStateActive() {
return false;
}
} //namespace bctoolbox
#endif
/*
* Copyright (c) 2010-2019 Belledonne Communications SARL.
*
* This file is part of Liblinphone.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "bctoolbox/ios_utils.hh"
namespace bctoolbox {
class IOSUtilsApp : public IOSUtilsInterface {
public:
unsigned long beginBackgroundTask(const char *name, std::function<void()> cb) override;
void endBackgroundTask(unsigned long id) override;
bool isApplicationStateActive() override;
};
} //namespace bctoolbox
/*
* Copyright (c) 2010-2019 Belledonne Communications SARL.
*
* This file is part of Liblinphone.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
#include <memory>
#include <UIKit/UIApplication.h>
#include "ios_utils_app.hh"
#include "bctoolbox/logging.h"
namespace bctoolbox {
unsigned long IOSUtilsApp::beginBackgroundTask(const char *name, std::function<void()> cb) {
__block UIBackgroundTaskIdentifier bgid = UIBackgroundTaskInvalid;
dispatch_block_t block = ^{
UIApplication *app=[UIApplication sharedApplication];
@try {
if (cb==nullptr){
bctbx_error("belle_sip_begin_background_task(): the callback must not be NULL. Application must be aware that the background task needs to be terminated.");
bgid = UIBackgroundTaskInvalid;
@throw([NSException exceptionWithName:@"LinphoneCoreException" reason:@"Background task has no callback" userInfo:nil]);
}
void (^handler)() = ^{
cb();
};
if([app respondsToSelector:@selector(beginBackgroundTaskWithName:expirationHandler:)]){
bgid = [app beginBackgroundTaskWithName:[NSString stringWithUTF8String:name] expirationHandler:handler];
} else {
bgid = [app beginBackgroundTaskWithExpirationHandler:handler];
}
if (bgid==UIBackgroundTaskInvalid){
bctbx_error("Could not start background task %s.", name);
bgid = 0;
@throw([NSException exceptionWithName:@"LinphoneCoreException" reason:@"Could not start background task" userInfo:nil]);
}
// backgroundTimeRemaining is properly set only when running background... but not immediately!
if (app.applicationState != UIApplicationStateBackground || (app.backgroundTimeRemaining == DBL_MAX)) {
bctbx_message("Background task %s started. Unknown remaining time since application is not fully in background.", name);
} else {
bctbx_message("Background task %s started. Remaining time %.1f secs", name, app.backgroundTimeRemaining);
}
}
@catch (NSException*) {
// do nothing
}
};
if( [NSThread isMainThread] ) {
block();
}
else {
dispatch_sync(dispatch_get_main_queue(), block);
}
return (unsigned long)bgid;
}
void IOSUtilsApp::endBackgroundTask(unsigned long id) {
dispatch_block_t block = ^{
UIApplication *app=[UIApplication sharedApplication];
if (id != UIBackgroundTaskInvalid){
[app endBackgroundTask:(UIBackgroundTaskIdentifier)id];
}
};
if( [NSThread isMainThread] ) {
block();
}
else {
dispatch_sync(dispatch_get_main_queue(), block);
}
}
bool IOSUtilsApp::isApplicationStateActive() {
return ([UIApplication sharedApplication].applicationState == UIApplicationStateActive);
}
} //namespace bctoolbox
extern "C" {
bctoolbox::IOSUtilsInterface *bctbx_create_ios_utils_app() {
return new bctoolbox::IOSUtilsApp;
}
void bctbx_destroy_ios_utils_app(bctoolbox::IOSUtilsInterface* p) {
delete p;
}
}
#endif
/*
* Copyright (c) 2010-2019 Belledonne Communications SARL.
*
* This file is part of Liblinphone.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "bctoolbox/ios_utils.hh"
namespace bctoolbox {
class IOSUtilsStub : public IOSUtilsInterface {
public:
unsigned long beginBackgroundTask(const char *name, std::function<void()> cb) override;
void endBackgroundTask(unsigned long id) override;
bool isApplicationStateActive() override;
};
} //namespace bctoolbox
......@@ -37,6 +37,9 @@ if(ENABLE_TESTS AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
if(MBEDTLS_FOUND OR POLARSSL_FOUND)
list(APPEND TESTER_SOURCES crypto.c)
endif()
if(APPLE)
list(APPEND TESTER_SOURCES ios_utils.cc)
endif()
string(REPLACE ";" " " LINK_FLAGS_STR "${LINK_FLAGS}")
......
......@@ -48,6 +48,9 @@ void bctoolbox_tester_init(void(*ftester_printf)(int level, const char *fmt, va_
bc_tester_add_suite(&crypto_test_suite);
#endif
bc_tester_add_suite(&parser_test_suite);
#ifdef __APPLE__
bc_tester_add_suite(&ios_utils_test_suite);
#endif
}
void bctoolbox_tester_uninit(void) {
......
......@@ -36,6 +36,7 @@ extern test_suite_t containers_test_suite;
extern test_suite_t utils_test_suite;
extern test_suite_t crypto_test_suite;
extern test_suite_t parser_test_suite;
extern test_suite_t ios_utils_test_suite;
#ifdef __cplusplus
};
......
/*
* Copyright (c) 2010-2019 Belledonne Communications SARL.
*
* This file is part of Liblinphone.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <dlfcn.h>
#include "bctoolbox_tester.h"
#include "bctoolbox/ios_utils.hh"
using namespace bctoolbox;
static void ios_utils_return_values(void) {
auto &iOSUtils = IOSUtils::getUtils();
BC_ASSERT_EQUAL(iOSUtils.beginBackgroundTask(nullptr, nullptr), 0, unsigned long, "%lu");
BC_ASSERT_EQUAL(iOSUtils.isApplicationStateActive(), false, bool, "%d");
}
static test_t ios_utils_tests[] = {
TEST_NO_TAG("Return values for stubbed functions", ios_utils_return_values),
};
test_suite_t ios_utils_test_suite = {"iOS Utilities", NULL, NULL, NULL, NULL,
sizeof(ios_utils_tests) / sizeof(ios_utils_tests[0]), ios_utils_tests};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment