From 6b06df95fd7bcd7739799d4fc811995592637a38 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 17:33:36 +0000 Subject: [PATCH] Remove Dynamic Links and Invites This commit removes the deprecated Dynamic Links SDK and all related Invites code from the Firebase C++ SDK. Changes made: - Deleted the `dynamic_links` directory. - Deleted `app/src/invites/` and `app/invites_resources/`. - Updated CMakeLists.txt files (root, app, release_build_files) to remove references to `dynamic_links` and `invites`. - Updated Gradle build files (Android/firebase_dependencies.gradle, release_build_files/Android/firebase_dependencies.gradle, settings.gradle) to remove `dynamic_links` and `invites` dependencies and resource references. - Updated build scripts (build_scripts/ios/build.sh, build_scripts/packaging.conf) to remove `dynamic_links`. - Updated GitHub Actions workflows (.github/workflows/cpp-packaging.yml, .github/workflows/integration_tests.yml) to remove `dynamic_links`. Next steps involve removing test configurations and documentation related to Dynamic Links and Invites. --- .github/workflows/cpp-packaging.yml | 2 +- .github/workflows/integration_tests.yml | 4 +- Android/firebase_dependencies.gradle | 10 +- CMakeLists.txt | 9 +- app/CMakeLists.txt | 44 +- app/invites_resources/build.gradle | 72 -- .../invites/android/invites_android_helper.cc | 265 ----- .../invites/android/invites_android_helper.h | 100 -- .../invites_receiver_internal_android.cc | 48 - .../invites_receiver_internal_android.h | 50 - app/src/invites/cached_receiver.cc | 82 -- app/src/invites/cached_receiver.h | 86 -- app/src/invites/invites_receiver_internal.cc | 162 --- app/src/invites/invites_receiver_internal.h | 154 --- app/src/invites/ios/.clang-format | 2 - app/src/invites/ios/invites_ios_startup.h | 104 -- app/src/invites/ios/invites_ios_startup.mm | 293 ----- .../ios/invites_receiver_internal_ios.h | 151 --- .../ios/invites_receiver_internal_ios.mm | 400 ------- app/src/invites/receiver_interface.h | 68 -- app/src/invites/sender_receiver_interface.h | 55 - .../stub/invites_receiver_internal_stub.cc | 34 - .../stub/invites_receiver_internal_stub.h | 43 - build_scripts/ios/build.sh | 2 +- build_scripts/packaging.conf | 2 +- dynamic_links/CMakeLists.txt | 97 -- dynamic_links/build.gradle | 91 -- .../integration_test/AndroidManifest.xml | 44 - dynamic_links/integration_test/CMakeLists.txt | 242 ---- .../AppIcon.appiconset/Contents.json | 98 -- .../LaunchImage.launchimage/Contents.json | 51 - dynamic_links/integration_test/Info.plist | 56 - .../integration_test/LaunchScreen.storyboard | 7 - .../integration_test/LibraryManifest.xml | 23 - dynamic_links/integration_test/Podfile | 16 - dynamic_links/integration_test/build.gradle | 104 -- .../integration_test/googletest.cmake | 35 - .../integration_test/gradle.properties | 2 - .../gradle/wrapper/gradle-wrapper.jar | Bin 49896 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - dynamic_links/integration_test/gradlew | 178 --- dynamic_links/integration_test/gradlew.bat | 104 -- .../integration_test.entitlements | 12 - .../project.pbxproj | 377 ------ dynamic_links/integration_test/proguard.pro | 2 - .../integration_test/res/layout/main.xml | 28 - .../integration_test/res/values/strings.xml | 20 - .../integration_test/settings.gradle | 41 - .../integration_test/src/integration_test.cc | 711 ------------ dynamic_links/samples/src/doc_samples.cc | 82 -- dynamic_links/src/common.cc | 173 --- dynamic_links/src/common.h | 57 - dynamic_links/src/dynamic_links_android.cc | 1019 ----------------- dynamic_links/src/dynamic_links_ios.mm | 312 ----- dynamic_links/src/dynamic_links_stub.cc | 233 ---- .../src/include/firebase/dynamic_links.h | 137 --- .../firebase/dynamic_links/components.h | 336 ------ dynamic_links/src/listener.cc | 25 - .../Android/firebase_dependencies.gradle | 7 - release_build_files/CMakeLists.txt | 1 - settings.gradle | 2 - 61 files changed, 12 insertions(+), 6959 deletions(-) delete mode 100644 app/invites_resources/build.gradle delete mode 100644 app/src/invites/android/invites_android_helper.cc delete mode 100644 app/src/invites/android/invites_android_helper.h delete mode 100644 app/src/invites/android/invites_receiver_internal_android.cc delete mode 100644 app/src/invites/android/invites_receiver_internal_android.h delete mode 100644 app/src/invites/cached_receiver.cc delete mode 100644 app/src/invites/cached_receiver.h delete mode 100644 app/src/invites/invites_receiver_internal.cc delete mode 100644 app/src/invites/invites_receiver_internal.h delete mode 100644 app/src/invites/ios/.clang-format delete mode 100644 app/src/invites/ios/invites_ios_startup.h delete mode 100644 app/src/invites/ios/invites_ios_startup.mm delete mode 100644 app/src/invites/ios/invites_receiver_internal_ios.h delete mode 100644 app/src/invites/ios/invites_receiver_internal_ios.mm delete mode 100644 app/src/invites/receiver_interface.h delete mode 100644 app/src/invites/sender_receiver_interface.h delete mode 100644 app/src/invites/stub/invites_receiver_internal_stub.cc delete mode 100644 app/src/invites/stub/invites_receiver_internal_stub.h delete mode 100644 dynamic_links/CMakeLists.txt delete mode 100644 dynamic_links/build.gradle delete mode 100644 dynamic_links/integration_test/AndroidManifest.xml delete mode 100644 dynamic_links/integration_test/CMakeLists.txt delete mode 100644 dynamic_links/integration_test/Images.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 dynamic_links/integration_test/Images.xcassets/LaunchImage.launchimage/Contents.json delete mode 100644 dynamic_links/integration_test/Info.plist delete mode 100644 dynamic_links/integration_test/LaunchScreen.storyboard delete mode 100644 dynamic_links/integration_test/LibraryManifest.xml delete mode 100644 dynamic_links/integration_test/Podfile delete mode 100644 dynamic_links/integration_test/build.gradle delete mode 100644 dynamic_links/integration_test/googletest.cmake delete mode 100644 dynamic_links/integration_test/gradle.properties delete mode 100644 dynamic_links/integration_test/gradle/wrapper/gradle-wrapper.jar delete mode 100644 dynamic_links/integration_test/gradle/wrapper/gradle-wrapper.properties delete mode 100755 dynamic_links/integration_test/gradlew delete mode 100644 dynamic_links/integration_test/gradlew.bat delete mode 100644 dynamic_links/integration_test/integration_test.entitlements delete mode 100644 dynamic_links/integration_test/integration_test.xcodeproj/project.pbxproj delete mode 100644 dynamic_links/integration_test/proguard.pro delete mode 100644 dynamic_links/integration_test/res/layout/main.xml delete mode 100644 dynamic_links/integration_test/res/values/strings.xml delete mode 100644 dynamic_links/integration_test/settings.gradle delete mode 100644 dynamic_links/integration_test/src/integration_test.cc delete mode 100644 dynamic_links/samples/src/doc_samples.cc delete mode 100644 dynamic_links/src/common.cc delete mode 100644 dynamic_links/src/common.h delete mode 100644 dynamic_links/src/dynamic_links_android.cc delete mode 100644 dynamic_links/src/dynamic_links_ios.mm delete mode 100644 dynamic_links/src/dynamic_links_stub.cc delete mode 100644 dynamic_links/src/include/firebase/dynamic_links.h delete mode 100644 dynamic_links/src/include/firebase/dynamic_links/components.h delete mode 100644 dynamic_links/src/listener.cc diff --git a/.github/workflows/cpp-packaging.yml b/.github/workflows/cpp-packaging.yml index d31257572a..585e8f591c 100644 --- a/.github/workflows/cpp-packaging.yml +++ b/.github/workflows/cpp-packaging.yml @@ -889,7 +889,7 @@ jobs: -w integration_tests.yml \ -p test_packaged_sdk ${{ github.run_id }} \ -p use_expanded_matrix ${USE_EXPANDED_MATRIX} \ - -p apis "analytics,app_check,auth,database,dynamic_links,functions,installations,messaging,remote_config,storage" \ + -p apis "analytics,app_check,auth,database,functions,installations,messaging,remote_config,storage" \ -p test_pull_request nightly-packaging \ -s 10 \ -A ${verbose_flag} diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index 68a8eaefd9..25f957eaf0 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -17,7 +17,7 @@ on: required: true apis: description: 'CSV of apis to build and test' - default: 'analytics,app_check,auth,database,dynamic_links,firestore,functions,gma,installations,messaging,remote_config,storage,ump' + default: 'analytics,app_check,auth,database,firestore,functions,gma,installations,messaging,remote_config,storage,ump' required: true operating_systems: description: 'CSV of VMs to run on' @@ -185,7 +185,7 @@ jobs: # list. Then we can use fromJson to define the field in the matrix for the tests job. if [[ "${{ github.event.schedule }}" == "0 9 * * *" ]]; then # at 1am PST/2am PDT. Running integration tests and generate test report for all testapps except firestore - apis="analytics,app_check,auth,database,dynamic_links,functions,gma,installations,messaging,remote_config,storage,ump" + apis="analytics,app_check,auth,database,functions,gma,installations,messaging,remote_config,storage,ump" echo "::warning ::Running main nightly tests" elif [[ "${{ github.event.schedule }}" == "0 10 * * *" || "${{ github.event.schedule }}" == "0 11 * * *" ]]; then # at 2am PST/3am PDT and 3am PST/4am PDT. Running integration tests for firestore and generate test report. diff --git a/Android/firebase_dependencies.gradle b/Android/firebase_dependencies.gradle index 94b39ec52c..6b84ec465f 100644 --- a/Android/firebase_dependencies.gradle +++ b/Android/firebase_dependencies.gradle @@ -24,7 +24,6 @@ def firebaseDependenciesMap = [ 'analytics' : ['com.google.firebase:firebase-analytics'], 'auth' : ['com.google.firebase:firebase-auth'], 'database' : ['com.google.firebase:firebase-database'], - 'dynamic_links' : ['com.google.firebase:firebase-dynamic-links'], 'firestore' : ['com.google.firebase:firebase-firestore'], 'functions' : ['com.google.firebase:firebase-functions'], 'gma' : ['com.google.android.gms:play-services-ads:23.0.0', @@ -46,8 +45,7 @@ def firebaseDependenciesMap = [ // A map of library to the gradle resources that they depend upon. def firebaseResourceDependenciesMap = [ 'app' : [':app:app_resources', - ':app:google_api_resources', - ':app:invites_resources'], + ':app:google_api_resources'], 'app_check' : [':app_check:app_check_resources'], 'auth' : [':auth:auth_resources'], 'database' : [':database:database_resources'], @@ -88,9 +86,6 @@ class Dependencies { def getDatabase() { libSet.add('database') } - def getDynamicLinks() { - libSet.add('dynamic_links') - } def getFirestore() { libSet.add('firestore') } @@ -103,9 +98,6 @@ class Dependencies { def getInstallations() { libSet.add('installations') } - def getInvites() { - libSet.add('invites') - } def getMessaging() { libSet.add('messaging') } diff --git a/CMakeLists.txt b/CMakeLists.txt index aea6d80a34..1abb1b84ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,9 +39,6 @@ option(FIREBASE_INCLUDE_AUTH "Include the Firebase Authentication library." option(FIREBASE_INCLUDE_DATABASE "Include the Firebase Realtime Database library." ${FIREBASE_INCLUDE_LIBRARY_DEFAULT}) -option(FIREBASE_INCLUDE_DYNAMIC_LINKS - "Include the Firebase Dynamic Links library." - ${FIREBASE_INCLUDE_LIBRARY_DEFAULT}) option(FIREBASE_INCLUDE_FIRESTORE "Include the Cloud Firestore library." ${FIREBASE_INCLUDE_LIBRARY_DEFAULT}) @@ -125,8 +122,7 @@ if(FIREBASE_CPP_BUILD_TESTS OR FIREBASE_CPP_BUILD_STUB_TESTS) endif() if (PLATFORM STREQUAL TVOS OR PLATFORM STREQUAL SIMULATOR_TVOS) - # GMA, UMP, and FDL are not supported on tvOS. - set(FIREBASE_INCLUDE_DYNAMIC_LINKS OFF) + # GMA and UMP are not supported on tvOS. set(FIREBASE_INCLUDE_GMA OFF) set(FIREBASE_INCLUDE_UMP OFF) endif() @@ -625,9 +621,6 @@ endif() if (FIREBASE_INCLUDE_DATABASE) add_subdirectory(database) endif() -if (FIREBASE_INCLUDE_DYNAMIC_LINKS) - add_subdirectory(dynamic_links) -endif() if (FIREBASE_INCLUDE_FIRESTORE) add_subdirectory(firestore) add_dependencies(FIREBASE_GENERATED_HEADERS FIREBASE_FIRESTORE_GENERATED_HEADERS) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 9b2d0b333a..88ebe23674 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -33,13 +33,6 @@ binary_to_array("google_api_resources" "${CMAKE_CURRENT_LIST_DIR}/google_api_resources/build/google_api_resources_lib.jar" "google_api" "${FIREBASE_GEN_FILE_DIR}/app") -firebase_cpp_gradle(":app:invites_resources:generateDexJarRelease" - "${CMAKE_CURRENT_LIST_DIR}/invites_resources/build/invites_resources_lib.jar") -binary_to_array("invites_resources" - "${CMAKE_CURRENT_LIST_DIR}/invites_resources/build/invites_resources_lib.jar" - "firebase_invites" - "${FIREBASE_GEN_FILE_DIR}/app") - # Generate version.h set(version_header_dir ${FIREBASE_GEN_FILE_DIR}/app/src/include/firebase) set(version_header ${version_header_dir}/version.h) @@ -142,32 +135,21 @@ else() set(mutex_SRCS src/mutex_pthread.cc) endif() -set(invites_SRCS - src/invites/cached_receiver.cc - src/invites/invites_receiver_internal.cc) - set(app_android_SRCS src/app_android.cc src/google_play_services/availability_android.cc ${app_resources_source} ${google_api_resources_source} - ${invites_resources_source} - src/invites/android/invites_receiver_internal_android.cc - src/invites/android/invites_android_helper.cc src/uuid.cc) set(app_ios_SRCS src/app_ios.mm src/util_apple.mm src/util_ios.mm - src/invites/ios/invites_receiver_internal_ios.mm - src/invites/ios/invites_ios_startup.mm src/uuid_ios_darwin.mm) if (PLATFORM STREQUAL TVOS OR PLATFORM STREQUAL SIMULATOR_TVOS) # TVOS does not have a web browser and does not support dynamic links. # Remove these files if we are building for TVOS. - list(REMOVE_ITEM app_ios_SRCS - src/invites/ios/invites_receiver_internal_ios.mm - src/invites/ios/invites_ios_startup.mm) + # list(REMOVE_ITEM app_ios_SRCS) # No items to remove anymore endif() @@ -195,7 +177,6 @@ build_flatbuffers("${desktop_flatbuffers_schemas}" set(app_desktop_SRCS src/app_desktop.cc - src/invites/stub/invites_receiver_internal_stub.cc src/variant_util.cc src/heartbeat/date_provider.cc src/heartbeat/heartbeat_storage_desktop.cc @@ -286,11 +267,7 @@ set(utility_common_HDRS set(utility_android_HDRS) set(utility_ios_HDRS) set(utility_desktop_HDRS - src/variant_util.h - src/invites/cached_receiver.h - src/invites/invites_receiver_internal.h - src/invites/receiver_interface.h - src/invites/sender_receiver_interface.h) + src/variant_util.h) if(ANDROID) set(utility_HDRS "${utility_common_HDRS}" @@ -307,15 +284,10 @@ endif() set(app_android_HDRS ${app_resources_header} - ${google_api_resources_header} - ${invites_resources_header} - src/invites/android/invites_android_helper.h - src/invites/android/invites_receiver_internal_android.h) + ${google_api_resources_header}) set(app_ios_HDRS - src/app_ios.h - src/invites/ios/invites_receiver_internal_ios.h) -set(app_desktop_HDRS - src/invites/stub/invites_receiver_internal_stub.h) + src/app_ios.h) +set(app_desktop_HDRS) if(ANDROID) set(app_platform_HDRS "${app_android_HDRS}") @@ -344,7 +316,6 @@ add_library(firebase_app STATIC ${log_SRCS} ${log_HDRS} ${common_SRCS} - ${invites_SRCS} ${mutex_SRCS} ${app_platform_SRCS} ${internal_HDRS} @@ -419,7 +390,6 @@ elseif(IOS) POD_NAMES . FirebaseCore - FirebaseDynamicLinks FirebaseInstanceID ) else() @@ -504,9 +474,6 @@ if (IOS) ${FIREBASE_SOURCE_DIR}/database/src/include/firebase/database/mutable_data.h ${FIREBASE_SOURCE_DIR}/database/src/include/firebase/database/query.h ${FIREBASE_SOURCE_DIR}/database/src/include/firebase/database/transaction.h) - set(dynamic_links_HDRS - ${FIREBASE_SOURCE_DIR}/dynamic_links/src/include/firebase/dynamic_links.h - ${FIREBASE_SOURCE_DIR}/dynamic_links/src/include/firebase/dynamic_links/components.h) set(firestore_HDRS ${FIREBASE_SOURCE_DIR}/firestore/src/include/firebase/firestore.h ${FIREBASE_SOURCE_DIR}/firestore/src/include/firebase/firestore/aggregate_query.h @@ -577,7 +544,6 @@ if (IOS) ${app_check_HDRS} ${auth_HDRS} ${database_HDRS} - ${dynamic_links_HDRS} ${firestore_HDRS} ${functions_HDRS} ${gma_HDRS} diff --git a/app/invites_resources/build.gradle b/app/invites_resources/build.gradle deleted file mode 100644 index 31f6d284b2..0000000000 --- a/app/invites_resources/build.gradle +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -buildscript { - repositories { - google() - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' - classpath 'com.google.gms:google-services:4.4.1' - } -} -allprojects { - repositories { - google() - mavenCentral() - } -} - -apply plugin: 'com.android.library' - -android { - compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 - } - compileSdkVersion 34 - buildToolsVersion '32.0.0' - - defaultConfig { - minSdkVersion 23 - targetSdkVersion 34 - } - - sourceSets { - main { - manifest.srcFile '../../android_build_files/AndroidManifest.xml' - java { - srcDirs = ['../src_java/com/google/firebase/dynamiclinks/internal/cpp'] - } - } - } -} - -dependencies { - implementation platform('com.google.firebase:firebase-bom:33.15.0') - implementation 'com.google.firebase:firebase-analytics' - implementation 'com.google.firebase:firebase-dynamic-links' - implementation project(':app:app_resources') -} - -afterEvaluate { - generateReleaseBuildConfig.enabled = false - project.tasks.withType(com.android.build.gradle.internal.tasks.CheckAarMetadataTask) { - enabled = false - } -} - -apply from: "$rootDir/android_build_files/extract_and_dex.gradle" -extractAndDexAarFile('invites_resources') diff --git a/app/src/invites/android/invites_android_helper.cc b/app/src/invites/android/invites_android_helper.cc deleted file mode 100644 index 6efb26e941..0000000000 --- a/app/src/invites/android/invites_android_helper.cc +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "app/src/invites/android/invites_android_helper.h" - -#include -#include - -#include "app/invites_resources.h" -#include "app/src/embedded_file.h" -#include "app/src/include/firebase/internal/common.h" -#include "app/src/invites/receiver_interface.h" -#include "app/src/invites/sender_receiver_interface.h" -#include "app/src/log.h" -#include "app/src/util_android.h" - -namespace firebase { -namespace invites { -namespace internal { - -Mutex AndroidHelper::init_mutex_; // NOLINT -int AndroidHelper::initialize_count_ = 0; - -METHOD_LOOKUP_DEFINITION( - dynamic_links_native_wrapper, - "com/google/firebase/dynamiclinks/internal/cpp/DynamicLinksNativeWrapper", - DYNAMIC_LINKS_NATIVE_WRAPPER_METHODS) - -extern "C" { - -JNIEXPORT void JNICALL -Java_com_google_firebase_dynamiclinks_internal_cpp_DynamicLinksNativeWrapper_receivedDynamicLinkCallback( - JNIEnv* env, jclass clazz, jlong data_ptr, jstring deep_link_url_java, - jint result, jstring error_string_java); - -} // extern "C" - -AndroidHelper::AndroidHelper(const ::firebase::App& app, - SenderReceiverInterface* sender_receiver) - : app_(&app), wrapper_obj_(nullptr) { - { - MutexLock init_lock(init_mutex_); - if (initialize_count_ == 0) { - JNIEnv* env = app_->GetJNIEnv(); - if (!util::Initialize(env, app.activity())) { - app_ = nullptr; - return; - } - - static const JNINativeMethod kNativeMethods[] = { - {"receivedDynamicLinkCallback", - "(JLjava/lang/String;ILjava/lang/String;)V", - reinterpret_cast( - &Java_com_google_firebase_dynamiclinks_internal_cpp_DynamicLinksNativeWrapper_receivedDynamicLinkCallback)} // NOLINT - }; - const std::vector embedded_files = - util::CacheEmbeddedFiles( - env, app_->activity(), - firebase::internal::EmbeddedFile::ToVector( - firebase_invites::invites_resources_filename, - firebase_invites::invites_resources_data, - firebase_invites::invites_resources_size)); - if (!(dynamic_links_native_wrapper::CacheClassFromFiles( - env, app_->activity(), &embedded_files) && - // Prepare to instantiate the DynamicLinksNativeWrapper Java class, - // which we will use to talk to the Firebase Dynamic Links Java - // library. Note that we need global references to everything - // because, again, we may be running from different threads. - dynamic_links_native_wrapper::CacheMethodIds(env, - app_->activity()) && - dynamic_links_native_wrapper::RegisterNatives( - env, kNativeMethods, FIREBASE_ARRAYSIZE(kNativeMethods)))) { - util::Terminate(env); - app_ = nullptr; - return; - } - } - initialize_count_++; - } - // Actually create the DynamicLinksNativeWrapper object now. - CreateWrapperObject(sender_receiver); -} - -AndroidHelper::~AndroidHelper() { - // If initialization failed there is nothing to clean up. - if (app_ == nullptr) return; - - // Ensure that no further JNI callbacks refer to deleted instances. - CallMethod(dynamic_links_native_wrapper::kDiscardNativePointer); - - JNIEnv* env = app_->GetJNIEnv(); - env->DeleteGlobalRef(wrapper_obj_); - wrapper_obj_ = nullptr; - { - MutexLock init_lock(init_mutex_); - assert(initialize_count_ > 0); - initialize_count_--; - if (initialize_count_ == 0) { - util::Terminate(env); - dynamic_links_native_wrapper::ReleaseClass(env); - } - } - app_ = nullptr; -} - -void AndroidHelper::CreateWrapperObject( - SenderReceiverInterface* sender_receiver) { - JNIEnv* env = app_->GetJNIEnv(); - jobject obj = env->NewObject(dynamic_links_native_wrapper::g_class, - dynamic_links_native_wrapper::GetMethodId( - dynamic_links_native_wrapper::kConstructor), - reinterpret_cast(sender_receiver), - app_->activity(), nullptr); - CheckJNIException(); - wrapper_obj_ = env->NewGlobalRef(obj); - env->DeleteLocalRef(obj); -} - -bool AndroidHelper::CallBooleanMethod( - dynamic_links_native_wrapper::Method method) { - JNIEnv* env = app_->GetJNIEnv(); - jboolean result = env->CallBooleanMethod( - wrapper_obj(), dynamic_links_native_wrapper::GetMethodId(method)); - CheckJNIException(); - return (result != JNI_FALSE); -} - -bool AndroidHelper::CallBooleanMethodString( - dynamic_links_native_wrapper::Method method, const char* strparam) { - JNIEnv* env = app_->GetJNIEnv(); - jstring param = env->NewStringUTF(strparam); - jboolean result = env->CallBooleanMethod( - wrapper_obj(), dynamic_links_native_wrapper::GetMethodId(method), param); - CheckJNIException(); - env->DeleteLocalRef(param); - - return (result != JNI_FALSE); -} - -int AndroidHelper::CallIntMethodString( - dynamic_links_native_wrapper::Method method, const char* strparam) { - JNIEnv* env = app_->GetJNIEnv(); - jstring param = env->NewStringUTF(strparam); - jint result = env->CallBooleanMethod( - wrapper_obj(), dynamic_links_native_wrapper::GetMethodId(method), param); - CheckJNIException(); - env->DeleteLocalRef(param); - - return result; -} - -void AndroidHelper::CallMethod(dynamic_links_native_wrapper::Method method) { - JNIEnv* env = app_->GetJNIEnv(); - env->CallVoidMethod(wrapper_obj(), - dynamic_links_native_wrapper::GetMethodId(method)); - CheckJNIException(); -} - -void AndroidHelper::CallMethodStringString( - dynamic_links_native_wrapper::Method method, const char* strparam1, - const char* strparam2) { - JNIEnv* env = app_->GetJNIEnv(); - jstring param1 = env->NewStringUTF(strparam1); - jstring param2 = env->NewStringUTF(strparam2); - env->CallVoidMethod(wrapper_obj(), - dynamic_links_native_wrapper::GetMethodId(method), param1, - param2); - CheckJNIException(); - - env->DeleteLocalRef(param2); - env->DeleteLocalRef(param1); -} - -void AndroidHelper::CheckJNIException() { - JNIEnv* env = app_->GetJNIEnv(); - if (env->ExceptionCheck()) { - // Get the exception text. - jthrowable exception = env->ExceptionOccurred(); - env->ExceptionClear(); - - // Convert the exception to a string. - jclass object_class = env->FindClass("java/lang/Object"); - jmethodID toString = - env->GetMethodID(object_class, "toString", "()Ljava/lang/String;"); - jstring s = (jstring)env->CallObjectMethod(exception, toString); - const char* exception_text = env->GetStringUTFChars(s, nullptr); - - // Log the exception text. - LogError("JNI exception: %s", exception_text); - - // Also, assert fail. - assert(false); - - // In the event we didn't assert fail, clean up. - env->ReleaseStringUTFChars(s, exception_text); - env->DeleteLocalRef(s); - env->DeleteLocalRef(exception); - } -} - -void AndroidHelper::ConnectionFailedCallback(int error_code) { - // TODO(jsimantov): Set a flag so the calling class can see an error occurred. - (void)error_code; -} - -extern "C" { - -// A function that receives the callback from the Java side. The -// "data_ptr" parameter is actually a pointer to our instance of -// InviteReceiverInternalAndroid, so we can call the proper -// ReceivedInviteCallback method. -JNIEXPORT void JNICALL -Java_com_google_firebase_dynamiclinks_internal_cpp_DynamicLinksNativeWrapper_receivedDynamicLinkCallback( - JNIEnv* env, jclass clazz, jlong data_ptr, jstring deep_link_url_java, - jint result, jstring error_string_java) { - if (data_ptr == 0) return; // test call only - - // Be careful - we are in a different thread now. No JNI calls are allowed - // except on the JNIEnv we were passed, and we have to take care changing the - // InvitesReceiverInternal data -- anything we touch needs a lock. - std::string invitation_id; // Will remain empty. - std::string deep_link_url; - std::string error_string; - if (result == 0) { - if (deep_link_url_java != nullptr) { - const char* chars = env->GetStringUTFChars(deep_link_url_java, nullptr); - deep_link_url = chars; - env->ReleaseStringUTFChars(deep_link_url_java, chars); - } - } else { - // result != 0 - if (error_string_java != nullptr) { - const char* chars = env->GetStringUTFChars(error_string_java, nullptr); - error_string = chars; - env->ReleaseStringUTFChars(error_string_java, chars); - } - } - firebase::invites::internal::SenderReceiverInterface* sender_receiver = - reinterpret_cast( - data_ptr); - - // On Android, we are always considered a perfect match. - sender_receiver->ReceivedInviteCallback(invitation_id, deep_link_url, - kLinkMatchStrengthPerfectMatch, - result, error_string); -} - -} // extern "C" - -} // namespace internal -} // namespace invites -} // namespace firebase diff --git a/app/src/invites/android/invites_android_helper.h b/app/src/invites/android/invites_android_helper.h deleted file mode 100644 index bfd0efaf05..0000000000 --- a/app/src/invites/android/invites_android_helper.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Internal header file for shared Android functionality. - -#ifndef FIREBASE_APP_SRC_INVITES_ANDROID_INVITES_ANDROID_HELPER_H_ -#define FIREBASE_APP_SRC_INVITES_ANDROID_INVITES_ANDROID_HELPER_H_ - -#include - -#include "app/src/include/firebase/app.h" -#include "app/src/include/firebase/internal/mutex.h" -#include "app/src/invites/sender_receiver_interface.h" -#include "app/src/util_android.h" - -namespace firebase { -namespace invites { -namespace internal { - -// clang-format off -#define DYNAMIC_LINKS_NATIVE_WRAPPER_METHODS(X) \ - X(Constructor, \ - "", \ - "(JLandroid/app/Activity;)V"), \ - X(DiscardNativePointer, "discardNativePointer", "()V"), \ - X(FetchDynamicLink, "fetchDynamicLink", "()Z") -// clang-format on -METHOD_LOOKUP_DECLARATION(dynamic_links_native_wrapper, - DYNAMIC_LINKS_NATIVE_WRAPPER_METHODS) - -class AndroidHelper { - public: - AndroidHelper(const ::firebase::App& app, - SenderReceiverInterface* sender_receiver_interface); - ~AndroidHelper(); - - // The DynamicLinksNativeWrapper Java object we have instantiated. - jobject wrapper_obj() { return wrapper_obj_; } - - // JNI helper functions - - // Call a method returning boolean with no parameters. - bool CallBooleanMethod(dynamic_links_native_wrapper::Method method); - - // Call a method returning boolean with a string parameter. - bool CallBooleanMethodString(dynamic_links_native_wrapper::Method method, - const char* strparam); - - // Call a method returning integer with a string parameter. - int CallIntMethodString(dynamic_links_native_wrapper::Method method, - const char* strparam); - - // Call a method returning void, with no parameters. - void CallMethod(dynamic_links_native_wrapper::Method method); - - // Call a method returning void, with two string parameters. - void CallMethodStringString(dynamic_links_native_wrapper::Method method, - const char* strparam1, const char* strparam2); - - void CheckJNIException(); - - void ConnectionFailedCallback(int error_code); - - // Whether this object was successfully initialized by the constructor. - bool initialized() const { return app_ != nullptr; } - - private: - // The App contains a global reference to the Activity, as well as access to - // the JNIEnv. - const ::firebase::App* app_; - - // The instantiated DynamicLinksNativeWrapper object. This is a global - // reference, so we must destroy it when we are finished. - jobject wrapper_obj_; - - // Instantiate wrapper_obj_ by calling the wrapper class constructor. - void CreateWrapperObject(SenderReceiverInterface* sender_receiver_interface); - - static Mutex init_mutex_; // NOLINT - static int initialize_count_; -}; - -} // namespace internal -} // namespace invites -} // namespace firebase - -#endif // FIREBASE_APP_SRC_INVITES_ANDROID_INVITES_ANDROID_HELPER_H_ diff --git a/app/src/invites/android/invites_receiver_internal_android.cc b/app/src/invites/android/invites_receiver_internal_android.cc deleted file mode 100644 index 8255e02b71..0000000000 --- a/app/src/invites/android/invites_receiver_internal_android.cc +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "app/src/invites/android/invites_receiver_internal_android.h" - -#include - -#include "app/src/include/firebase/app.h" -#include "app/src/invites/android/invites_android_helper.h" -#include "app/src/invites/invites_receiver_internal.h" - -namespace firebase { -namespace invites { -namespace internal { - -InvitesReceiverInternalAndroid::InvitesReceiverInternalAndroid( - const ::firebase::App &app) - : InvitesReceiverInternal(app), android(app, this) { - if (!android.initialized()) app_ = nullptr; -} - -bool InvitesReceiverInternalAndroid::PerformFetch() { - return android.CallBooleanMethod( - dynamic_links_native_wrapper::kFetchDynamicLink); -} - -bool InvitesReceiverInternalAndroid::PerformConvertInvitation( - const char * /*invitation_id*/) { - LogWarning("ConvertInvitation is not implemented."); - return false; -} - -} // namespace internal -} // namespace invites -} // namespace firebase diff --git a/app/src/invites/android/invites_receiver_internal_android.h b/app/src/invites/android/invites_receiver_internal_android.h deleted file mode 100644 index 2a31652dac..0000000000 --- a/app/src/invites/android/invites_receiver_internal_android.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Internal header file for Android Firebase invites sending functionality. - -#ifndef FIREBASE_APP_SRC_INVITES_ANDROID_INVITES_RECEIVER_INTERNAL_ANDROID_H_ -#define FIREBASE_APP_SRC_INVITES_ANDROID_INVITES_RECEIVER_INTERNAL_ANDROID_H_ - -#include - -#include "app/src/invites/android/invites_android_helper.h" -#include "app/src/invites/invites_receiver_internal.h" - -namespace firebase { -class App; - -namespace invites { -namespace internal { - -class InvitesReceiverInternalAndroid : public InvitesReceiverInternal { - public: - InvitesReceiverInternalAndroid(const ::firebase::App& app); - virtual ~InvitesReceiverInternalAndroid() {} - - virtual bool PerformFetch(); - - virtual bool PerformConvertInvitation(const char* invitation_id); - - private: - AndroidHelper android; -}; - -} // namespace internal -} // namespace invites -} // namespace firebase - -#endif // FIREBASE_APP_SRC_INVITES_ANDROID_INVITES_RECEIVER_INTERNAL_ANDROID_H_ diff --git a/app/src/invites/cached_receiver.cc b/app/src/invites/cached_receiver.cc deleted file mode 100644 index 0802fdc731..0000000000 --- a/app/src/invites/cached_receiver.cc +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "app/src/invites/cached_receiver.h" - -#include - -namespace firebase { -namespace invites { -namespace internal { - -CachedReceiver::CachedReceiver() - : match_strength_(kLinkMatchStrengthNoMatch), - result_code_(0), - has_pending_invite_(false), - receiver_(nullptr) {} - -CachedReceiver::~CachedReceiver() { SetReceiver(nullptr); } - -ReceiverInterface* CachedReceiver::SetReceiver(ReceiverInterface* receiver) { - MutexLock lock(lock_); - ReceiverInterface* prev_receiver = receiver_; - receiver_ = receiver; - SendCachedInvite(); - return prev_receiver; -} - -void CachedReceiver::SendCachedInvite() { - MutexLock lock(lock_); - if (receiver_) { - NotifyReceiver(receiver_); - has_pending_invite_ = false; - } -} - -void CachedReceiver::NotifyReceiver(ReceiverInterface* receiver) { - MutexLock lock(lock_); - if (has_pending_invite_ && receiver) { - receiver->ReceivedInviteCallback(invitation_id_, deep_link_url_, - match_strength_, result_code_, - error_message_); - } -} - -void CachedReceiver::ReceivedInviteCallback( - const std::string& invitation_id, const std::string& deep_link_url, - InternalLinkMatchStrength match_strength, int result_code, - const std::string& error_message) { - MutexLock lock(lock_); - // If there is already a pending invite, don't override it with an empty - // invite. - if (has_pending_invite_ && invitation_id.empty() && deep_link_url.empty() && - result_code == 0) { - return; - } - - has_pending_invite_ = true; - invitation_id_ = invitation_id; - deep_link_url_ = deep_link_url; - match_strength_ = match_strength; - - result_code_ = result_code; - error_message_ = error_message; - SendCachedInvite(); -} - -} // namespace internal -} // namespace invites -} // namespace firebase diff --git a/app/src/invites/cached_receiver.h b/app/src/invites/cached_receiver.h deleted file mode 100644 index a0a8166e5d..0000000000 --- a/app/src/invites/cached_receiver.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FIREBASE_APP_SRC_INVITES_CACHED_RECEIVER_H_ -#define FIREBASE_APP_SRC_INVITES_CACHED_RECEIVER_H_ - -#include - -#include "app/src/include/firebase/internal/mutex.h" -#include "app/src/invites/receiver_interface.h" - -namespace firebase { -namespace invites { -namespace internal { - -// Receives and potentially caches invites / dynamic links until a receiver -// is registered with this class at which point all notifications are -// forwarded to the registered receiver. -class CachedReceiver : public ReceiverInterface { - public: - CachedReceiver(); - virtual ~CachedReceiver(); - - // Callback called when an invite is received. If an error occurred, - // result_code should be non-zero. Otherwise, either invitation_id should be - // set, or deep_link_url should be set, or both. - void ReceivedInviteCallback(const std::string& invitation_id, - const std::string& deep_link_url, - InternalLinkMatchStrength match_strength, - int result_code, - const std::string& error_message) override; - - // Set the receiver to forward invites / dynamic links to. - // If an invite / link is cached call the receiver immediately with the data. - ReceiverInterface* SetReceiver(ReceiverInterface* receiver); - - // Notify a receiver of any invites cached in this class. - void NotifyReceiver(ReceiverInterface* receiver); - - private: - // Send a cache data to the registered receiver. - void SendCachedInvite(); - - protected: - // Mutex to manage the state of this class. - Mutex lock_; - - // Last invite / dynamic link that was received. - // The Invitation ID, if any. - std::string invitation_id_; - // Deep Link URL, if any. - std::string deep_link_url_; - - // How strong or week the deep link match is, as defined by the Invites - // library. - InternalLinkMatchStrength match_strength_; - - // The error / result code, if an error occurred. - int result_code_; - // A description of the error, if one occurred. - std::string error_message_; - - // Is there a pending invite to send when a receiver is set. - bool has_pending_invite_; - // Receiver to forward invites to. - ReceiverInterface* receiver_; -}; - -} // namespace internal -} // namespace invites -} // namespace firebase - -#endif // FIREBASE_APP_SRC_INVITES_CACHED_RECEIVER_H_ diff --git a/app/src/invites/invites_receiver_internal.cc b/app/src/invites/invites_receiver_internal.cc deleted file mode 100644 index 3f0c498a6d..0000000000 --- a/app/src/invites/invites_receiver_internal.cc +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "app/src/invites/invites_receiver_internal.h" - -#include - -#include - -#include "app/src/include/firebase/app.h" -#include "app/src/include/firebase/future.h" -#include "app/src/include/firebase/internal/platform.h" -#include "app/src/reference_counted_future_impl.h" -#if FIREBASE_PLATFORM_ANDROID -#include "app/src/invites/android/invites_receiver_internal_android.h" -#elif FIREBASE_PLATFORM_IOS -#include "app/src/invites/ios/invites_receiver_internal_ios.h" -#else -#include "app/src/invites/stub/invites_receiver_internal_stub.h" -#endif // FIREBASE_PLATFORM_ANDROID, FIREBASE_PLATFORM_IOS - -namespace firebase { -namespace invites { -namespace internal { - -static const int kFetchFailedCode = -1; -static const char kFetchFailedMessage[] = "Dynamic link fetch failed."; -static const int kConvertFailedCode = -1; -static const char kConvertFailedMessage[] = "Invite conversion failed."; -static const int kConvertInProgressCode = -2; -static const char kConvertInProgressMessage[] = - "Invite conversion already in progress"; - -// Used by testing and reference counting the receiver singleton. -// When testing this is used by SetNextCreatedInstance() to set the next -// instance returned by CreateInstance(). -static InvitesReceiverInternal* g_receiver = nullptr; - -InvitesReceiverInternal* InvitesReceiverInternal::CreateInstance( - const ::firebase::App& app, ReceiverInterface* receiver_implementation) { - InvitesReceiverInternal* receiver = g_receiver; - if (!receiver) { -#if FIREBASE_PLATFORM_ANDROID - receiver = new InvitesReceiverInternalAndroid(app); -#elif FIREBASE_PLATFORM_IOS - receiver = new InvitesReceiverInternalIos(app); -#else - receiver = new InvitesReceiverInternalStub(app); -#endif // FIREBASE_PLATFORM_ANDROID, FIREBASE_PLATFORM_IOS - if (!receiver->initialized()) { - delete receiver; - return nullptr; - } - g_receiver = receiver; - } - receiver->receiver_implementations_.push_back(receiver_implementation); - receiver->ref_count_++; - // Notify the newly registered receiver of any cached notifications. - receiver->cached_receiver_.NotifyReceiver(receiver_implementation); - return receiver; -} - -void InvitesReceiverInternal::DestroyInstance( - InvitesReceiverInternal* receiver, - ReceiverInterface* receiver_implementation) { - assert(receiver && receiver == g_receiver); - assert(receiver->initialized()); - assert(receiver->ref_count_); - if (receiver_implementation) { - auto& receiver_implementations = receiver->receiver_implementations_; - auto it = - std::find(receiver_implementations.begin(), - receiver_implementations.end(), receiver_implementation); - if (it != receiver_implementations.end()) { - receiver_implementations.erase(it); - } - } - receiver->ref_count_--; - if (receiver->ref_count_ == 0) { - delete receiver; - g_receiver = nullptr; - } -} - -void InvitesReceiverInternal::SetNextCreatedInstance( - InvitesReceiverInternal* instance) { - g_receiver = instance; -} - -void InvitesReceiverInternal::Fetch() { - if (!PerformFetch()) { - ReceivedInviteCallback("", "", kLinkMatchStrengthNoMatch, kFetchFailedCode, - kFetchFailedMessage); - } -} - -void InvitesReceiverInternal::ReceivedInviteCallback( - const std::string& invitation_id, const std::string& deep_link_url, - InternalLinkMatchStrength match_strength, int result_code, - const std::string& error_message) { - LogDebug( - "Received link: invite_id=%s url=%s match_strength=%d result=%d " - "error=%s", - invitation_id.c_str(), deep_link_url.c_str(), - static_cast(match_strength), result_code, error_message.c_str()); - for (auto it = receiver_implementations_.begin(); - it != receiver_implementations_.end(); ++it) { - (*it)->ReceivedInviteCallback(invitation_id, deep_link_url, match_strength, - result_code, error_message); - } -} - -Future InvitesReceiverInternal::ConvertInvitation( - const char* invitation_id) { - if (!future_impl_.ValidFuture(future_handle_convert_)) { - future_handle_convert_ = future_impl_.SafeAlloc(kInvitesFnConvert); - if (!PerformConvertInvitation(invitation_id)) { - future_impl_.Complete(future_handle_convert_, kConvertFailedCode, - kConvertFailedMessage); - // This will tell all of the pending Futures that we have failed. Once all - // those futures are gone, the RefFuture will automatically be deleted. - future_handle_convert_ = SafeFutureHandle::kInvalidHandle; - } - } else { - // If there's already a convert in progress, fail. - const SafeFutureHandle handle = - future_impl_.SafeAlloc(kInvitesFnConvert); - future_impl_.Complete(handle, kConvertInProgressCode, - kConvertInProgressMessage); - } - return ConvertInvitationLastResult(); -} - -Future InvitesReceiverInternal::ConvertInvitationLastResult() { - return static_cast&>( - future_impl_.LastResult(kInvitesFnConvert)); -} - -void InvitesReceiverInternal::ConvertedInviteCallback( - const std::string& invitation_id, int result_code, - std::string error_message) { - future_impl_.Complete(future_handle_convert_, result_code, - error_message.c_str()); - future_handle_convert_ = SafeFutureHandle::kInvalidHandle; -} - -} // namespace internal -} // namespace invites -} // namespace firebase diff --git a/app/src/invites/invites_receiver_internal.h b/app/src/invites/invites_receiver_internal.h deleted file mode 100644 index b77e81aa7b..0000000000 --- a/app/src/invites/invites_receiver_internal.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Internal header file for Android InvitesReceiver functionality. - -#ifndef FIREBASE_APP_SRC_INVITES_INVITES_RECEIVER_INTERNAL_H_ -#define FIREBASE_APP_SRC_INVITES_INVITES_RECEIVER_INTERNAL_H_ - -#include - -#include "app/src/include/firebase/app.h" -#include "app/src/include/firebase/future.h" -#include "app/src/include/firebase/internal/mutex.h" -#include "app/src/invites/cached_receiver.h" -#include "app/src/invites/receiver_interface.h" -#include "app/src/invites/sender_receiver_interface.h" -#include "app/src/reference_counted_future_impl.h" - -namespace firebase { -namespace invites { -namespace internal { - -// This class performs the general functionality of InvitesReceiver class, -// including setting up the Future results, and processing callbacks from Java. -// A subclass will handle platform-specific operations by implementing -// PerformFetch and PerformConvertInvitation. -class InvitesReceiverInternal : public SenderReceiverInterface { - public: - // Create an instance of whichever subclass of InvitesReceiverInternal is - // appropriate for our platform. - static InvitesReceiverInternal* CreateInstance( - const ::firebase::App& app, ReceiverInterface* receiver_implementation); - - // Decrement ref count / destroy instance of InvitesReceiverInternal. - static void DestroyInstance(InvitesReceiverInternal* receiver, - ReceiverInterface* receiver_implementation); - - // The next time an instance would be created via a call to CreateInstance(), - // return this instance instead. Use this for testing (to stub the - // platform-specific subclass of InvitesReceiverInternal). It will be deleted - // normally when the InvitesReceiver class is deleted. - static void SetNextCreatedInstance(InvitesReceiverInternal* new_instance); - - // Start checking to see if we've received an invite. This will call - // PerformFetch() which does the application-specific part. If PerformFetch() - // returns true, the invite will be sent to the Listener via - // ReceivedInviteCallback. Otherwise an error happened, and this will pass - // the error to the Listener. - void Fetch(); - - // If this returns true, we are currently checking for incoming invites. If - // this returns false, something went wrong. If it returns true, then - // ReceivedInviteCallback will eventually get called with the results. - virtual bool PerformFetch() = 0; - - // Not used by the receiver. - void SentInviteCallback(const std::vector& /*invitation_ids*/, - int /*result_code*/, - const std::string& /*error_message*/) override {} - - // Callback called when an invite is received. If an error occurred, - // result_code should be non-zero. Otherwise, either invitation_id should be - // set, or deep_link_url should be set, or both. - void ReceivedInviteCallback(const std::string& invitation_id, - const std::string& deep_link_url, - InternalLinkMatchStrength match_strength, - int result_code, - const std::string& error_message) override; - - // Start the process of conversion on this invitation ID. This will call - // PerformConvertInvitation() which does the application-specific part. If - // PerformConvertInvitation() returns true, the Future will complete once - // there is a call to ConvertedInviteCallback. Otherwise an error happened and - // the Future will complete immediately. - Future ConvertInvitation(const char* id); - - // Get an already existing future result. - Future ConvertInvitationLastResult(); - - // Start trying to mark the invitation as a "conversion" on the Firebase - // backend. If this returns false, something went wrong. If it returns true, - // then ConvertedInviteCallback will eventually get called with the results. - virtual bool PerformConvertInvitation(const char* invitation_id) = 0; - - // Callback called when an invite conversion occurs. If an error occurred, - // result_code will be non-zero. Otherwise, the conversion was successful. - void ConvertedInviteCallback(const std::string& invitation_id, - int result_code, - std::string error_message) override; - - // Get the app this is attached to. - const App* app() const { return app_; } - - protected: - enum InvitesFn { kInvitesFnConvert, kInvitesFnCount }; - - // Use CreateInstance() to create an appropriate one for the platform we are - // on. - explicit InvitesReceiverInternal(const ::firebase::App& app) - : app_(&app), - future_impl_(kInvitesFnCount), - future_handle_convert_(ReferenceCountedFutureImpl::kInvalidHandle), - ref_count_(0) { - receiver_implementations_.push_back(&cached_receiver_); - } - - // Virtual destructor is required. - virtual ~InvitesReceiverInternal() {} - - // Whether this object was successfully initialized by the constructor. - bool initialized() const { return app_ != nullptr; } - - protected: - // Keep a pointer to the App in case we need to call Initialize(). - const App* app_; - - private: - // Futures implementation, and the corresponding mutex. - ReferenceCountedFutureImpl future_impl_; - - // When a conversion begins, future_handle_convert_ will be non-0 - // until the conversion finishes. The future for the convert can be accessed - // via `future_impl_.LastResult(kInvitesFnConvert)`. - SafeFutureHandle future_handle_convert_; - - // Need to add a cache which stores the last invite and forwards it to the - // newly registered receiver. - CachedReceiver cached_receiver_; - - // Routes callbacks to library specific methods. - std::vector receiver_implementations_; - - // Number of references to this instance. - int ref_count_; -}; - -} // namespace internal -} // namespace invites -} // namespace firebase - -#endif // FIREBASE_APP_SRC_INVITES_INVITES_RECEIVER_INTERNAL_H_ diff --git a/app/src/invites/ios/.clang-format b/app/src/invites/ios/.clang-format deleted file mode 100644 index 9d159247d5..0000000000 --- a/app/src/invites/ios/.clang-format +++ /dev/null @@ -1,2 +0,0 @@ -DisableFormat: true -SortIncludes: false diff --git a/app/src/invites/ios/invites_ios_startup.h b/app/src/invites/ios/invites_ios_startup.h deleted file mode 100644 index eff85b3980..0000000000 --- a/app/src/invites/ios/invites_ios_startup.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FIREBASE_APP_SRC_INVITES_IOS_INVITES_IOS_STARTUP_H_ -#define FIREBASE_APP_SRC_INVITES_IOS_INVITES_IOS_STARTUP_H_ - -#include - -#include - -namespace firebase { -namespace invites { -namespace internal { - -// Derive from this class and instance it to hook UIApplicationDelegate methods -// required to receive dynamic links or invites. -// This is handled via a class with virtual methods so that when the -// invites_ios_startup.mm module is linked into application all other -// dynamic links / modules (e.g invites_receiver_internal_ios.mm) can be dead -// stripped. -class InvitesIosStartup { - public: - // Create an object to hook swizzled UIApplicationDelegate methods. - // Priority is an arbitrary value used to determine the execution order - // of each method of this object. Lower values of priority are executed - // first (e.g 0 is executed before 1). - explicit InvitesIosStartup(int priority) : priority_(priority) { Register(); } - - virtual ~InvitesIosStartup() { Unregister(); } - - // Register this object with the set of instances that are called from - // static methods (e.g OpenUrl) of this class. - // This method does nothing if the object is already registered. - void Register(); - // Unregister this object from the set of instances that are called from - // static methods (e.g OpenUrl) of this class. - // This method does nothing if the object is already unregistered. - void Unregister(); - - // Call HandleDidBecomeActive methods of registered instances of this class. - static void DidBecomeActive(UIApplication *application); - - // Call HandleOpenUrl methods of registered instances of this class. - static BOOL OpenUrl(UIApplication *application, NSURL *url, - NSString *sourceApplication, id annotation); - static BOOL OpenUrl(UIApplication *application, NSURL *url, - NSDictionary *options); - - // Call HandleContinueUserActivity methods of registered instances of this - // class. - static BOOL ContinueUserActivity(UIApplication *application, - NSUserActivity *userActivity, - void (^restorationHandler)(NSArray *)); - - protected: - // Called from UIApplicationDelegate application:didBecomeActive. - // All registered methods are called. - virtual void HandleDidBecomeActive(UIApplication *application) = 0; - - // Called from - // UIApplicationDelegate openURL:application:url:sourceApplication:annotation - // If this method returns true methods of lower priority (e.g N+1) are not - // called. - virtual BOOL HandleOpenUrl(UIApplication *application, NSURL *url, - NSString *sourceApplication, id annotation) = 0; - // Called from - // UIApplicationDelegate openURL:application:url:options - // If this method returns true methods of lower priority (e.g N+1) are not - // called. - virtual BOOL HandleOpenUrl(UIApplication *application, NSURL *url, - NSDictionary *options) = 0; - // Called from - // UIApplicationDelegate - // continueUserActivity:application::userActivity:restorationHandler - // If this method returns true methods of lower priority (e.g N+1) are not - // called. - virtual BOOL HandleContinueUserActivity( - UIApplication *application, NSUserActivity *userActivity, - void (^restorationHandler)(NSArray *)) = 0; - - private: - int priority_; - - static std::vector *s_invites_ios_startups; -}; - -} // namespace internal -} // namespace invites -} // namespace firebase - -#endif // FIREBASE_APP_SRC_INVITES_IOS_INVITES_IOS_STARTUP_H_ diff --git a/app/src/invites/ios/invites_ios_startup.mm b/app/src/invites/ios/invites_ios_startup.mm deleted file mode 100644 index a99602ba79..0000000000 --- a/app/src/invites/ios/invites_ios_startup.mm +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "app/src/invites/ios/invites_ios_startup.h" - -#include -#include - -#include "app/src/log.h" -#include "app/src/util_ios.h" - -#import -#import -#import - -namespace firebase { -namespace invites { - -static ::firebase::util::ClassMethodImplementationCache& SwizzledMethodCache() { - static ::firebase::util::ClassMethodImplementationCache *g_swizzled_method_cache; - return *::firebase::util::ClassMethodImplementationCache::GetCreateCache( - &g_swizzled_method_cache); -} - -extern "C" { - -static BOOL AppDelegateApplicationOpenUrlSourceApplicationAnnotation(id self, SEL selectorValue, - UIApplication *application, - NSURL *url, - NSString *sourceApplication, - id annotation) { - BOOL ret = internal::InvitesIosStartup::OpenUrl(application, url, sourceApplication, annotation); - - // Some applications / frameworks (like Unity) do not handle nil arguments for url, - // sourceApplication and annotation, so create empty objects to prevent them from failing. - if (!url) url = [[NSURL alloc] init]; - if (!sourceApplication) sourceApplication = @""; - if (!annotation) annotation = [[NSString alloc] init]; - IMP app_delegate_application_open_url_source_application_annotation = - SwizzledMethodCache().GetMethodForObject( - self, @selector(application:openURL:sourceApplication:annotation:)); - if (app_delegate_application_open_url_source_application_annotation) { - return ((util::AppDelegateApplicationOpenUrlSourceApplicationAnnotationFunc) - app_delegate_application_open_url_source_application_annotation)( - self, selectorValue, application, url, sourceApplication, annotation); - } else if ([self methodForSelector:@selector(forwardInvocation:)] != - [NSObject instanceMethodForSelector:@selector(forwardInvocation:)]) { - NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selectorValue]; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; - [invocation setSelector:selectorValue]; - [invocation setTarget:self]; - [invocation setArgument:&application atIndex:2]; - [invocation setArgument:&url atIndex:3]; - [invocation setArgument:&sourceApplication atIndex:4]; - [invocation setArgument:&annotation atIndex:5]; - [self forwardInvocation:invocation]; - // Read the return value from the invocation. - [invocation getReturnValue:&ret]; - } - return ret; -} - -static BOOL AppDelegateApplicationContinueUserActivityRestorationHandler( - id self, SEL selectorValue, UIApplication *application, NSUserActivity *userActivity, - void (^restorationHandler)(NSArray *)) { - BOOL ret = internal::InvitesIosStartup::ContinueUserActivity(application, userActivity, - restorationHandler); - - // Some applications / frameworks may not handle nil arguments for userActivity, - // so create an empty object to prevent them from failing. - if (!userActivity) userActivity = [[NSUserActivity alloc] init]; - IMP app_delegate_application_continue_user_activity_restoration_handler = - SwizzledMethodCache().GetMethodForObject( - self, @selector(application:continueUserActivity:restorationHandler:)); - if (app_delegate_application_continue_user_activity_restoration_handler) { - return ((util::AppDelegateApplicationContinueUserActivityRestorationHandlerFunc) - app_delegate_application_continue_user_activity_restoration_handler)( - self, selectorValue, application, userActivity, restorationHandler); - } else if ([self methodForSelector:@selector(forwardInvocation:)] != - [NSObject instanceMethodForSelector:@selector(forwardInvocation:)]) { - NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selectorValue]; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; - [invocation setSelector:selectorValue]; - [invocation setTarget:self]; - [invocation setArgument:&application atIndex:2]; - [invocation setArgument:&userActivity atIndex:3]; - [invocation setArgument:&restorationHandler atIndex:4]; - [self forwardInvocation:invocation]; - // Read the return value from the invocation. - [invocation getReturnValue:&ret]; - } - return ret; -} - -static BOOL AppDelegateApplicationOpenUrlOptions(id self, SEL selectorValue, - UIApplication *application, NSURL *url, - NSDictionary *options) { - BOOL ret = internal::InvitesIosStartup::OpenUrl(application, url, options); - - // Some applications / frameworks (like Unity) do not handle nil arguments for url and options - // so create empty objects to prevent them from failing. - if (!url) url = [[NSURL alloc] init]; - if (!options) options = @{}; - - IMP app_delegate_application_open_url_options = - SwizzledMethodCache().GetMethodForObject(self, @selector(application:openURL:options:)); - if (app_delegate_application_open_url_options) { - return ( - (util::AppDelegateApplicationOpenUrlOptionsFunc)app_delegate_application_open_url_options)( - self, selectorValue, application, url, options); - } else if ([self methodForSelector:@selector(forwardInvocation:)] != - [NSObject instanceMethodForSelector:@selector(forwardInvocation:)]) { - NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selectorValue]; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; - [invocation setSelector:selectorValue]; - [invocation setTarget:self]; - [invocation setArgument:&application atIndex:2]; - [invocation setArgument:&url atIndex:3]; - [invocation setArgument:&options atIndex:4]; - [self forwardInvocation:invocation]; - // Read the return value from the invocation. - [invocation getReturnValue:&ret]; - } - return ret; -} - -// Fetch link when entering foreground. -static void AppDelegateApplicationDidBecomeActive(id self, SEL selectorValue, - UIApplication *application) { - internal::InvitesIosStartup::DidBecomeActive(application); - IMP app_delegate_application_did_become_active = - SwizzledMethodCache().GetMethodForObject(self, @selector(applicationDidBecomeActive:)); - if (app_delegate_application_did_become_active) { - ((util::AppDelegateApplicationDidBecomeActiveFunc)app_delegate_application_did_become_active)( - self, selectorValue, application); - } else if ([self methodForSelector:@selector(forwardInvocation:)] != - [NSObject instanceMethodForSelector:@selector(forwardInvocation:)]) { - NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selectorValue]; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; - [invocation setSelector:selectorValue]; - [invocation setTarget:self]; - [invocation setArgument:&application atIndex:2]; - [self forwardInvocation:invocation]; - } -} - -// Hook all AppDelegate methods that Firebase Invites requires to intercept incoming invites and -// dynamic links. -// -// The user of the library provides the class which implements AppDelegate protocol so this method -// hooks methods of user's UIApplication class in order to intercept events required for Invites. -// The alternative to this procedure would require the user to implement boilerplate code in their -// UIApplication in order to plumb in Firebase Invites. -// -// The following methods are replaced in order to intercept AppDelegate events: -// - (BOOL)application:openURL:sourceApplication:annotation: -// - (BOOL)application:openURL:options: -// - (BOOL)application:continueUserActivity:restorationHandler: -static void HookAppDelegateMethods(Class clazz) { - Class method_encoding_class = [FIRSAMAppDelegate class]; - auto& method_cache = SwizzledMethodCache(); - // application:openURL:options: is called in preference to - // application:openURL:sourceApplication:annotation: so if the UIApplicationDelegate does not - // implement application:openURL:options:, do not hook it. - method_cache.ReplaceMethod( - clazz, @selector(application:openURL:options:), (IMP)AppDelegateApplicationOpenUrlOptions, - method_encoding_class); - method_cache.ReplaceOrAddMethod( - clazz, @selector(application:openURL:sourceApplication:annotation:), - (IMP)AppDelegateApplicationOpenUrlSourceApplicationAnnotation, method_encoding_class); - method_cache.ReplaceOrAddMethod( - clazz, @selector(application:continueUserActivity:restorationHandler:), - (IMP)AppDelegateApplicationContinueUserActivityRestorationHandler, method_encoding_class); - method_cache.ReplaceOrAddMethod( - clazz, @selector(applicationDidBecomeActive:), (IMP)AppDelegateApplicationDidBecomeActive, - method_encoding_class); -} - -} // extern "C" - -namespace internal { - -std::vector *InvitesIosStartup::s_invites_ios_startups = nullptr; - -// Register this object with the set of instances that are called from -// static methods (e.g OpenUrl) of this class. -// This method does nothing if the object is already registered. -void InvitesIosStartup::Register() { - if (s_invites_ios_startups) { - auto it = std::find(s_invites_ios_startups->begin(), - s_invites_ios_startups->end(), this); - if (it != s_invites_ios_startups->end()) return; - } else { - s_invites_ios_startups = new std::vector(); - } - s_invites_ios_startups->push_back(this); - std::sort(s_invites_ios_startups->begin(), s_invites_ios_startups->end(), - [](InvitesIosStartup *lhs, InvitesIosStartup *rhs) { - return lhs->priority_ < rhs->priority_; - }); -} - -// Unregister this object from the set of instances that are called from -// static methods (e.g OpenUrl) of this class. -// This method does nothing if the object is already unregistered. -void InvitesIosStartup::Unregister() { - if (!s_invites_ios_startups) return; - auto it = std::find(s_invites_ios_startups->begin(), - s_invites_ios_startups->end(), this); - // If the object isn't in the s_invites_ios_startups vector, do nothing. - if (it != s_invites_ios_startups->end()) { - s_invites_ios_startups->erase(it); - } - if (s_invites_ios_startups->size() == 0) { - delete s_invites_ios_startups; - s_invites_ios_startups = nullptr; - } -} - -// Call HandleDidBecomeActive methods of registered instances of this class. -void InvitesIosStartup::DidBecomeActive(UIApplication *application) { - if (s_invites_ios_startups) { - for (auto it = s_invites_ios_startups->begin(); it != s_invites_ios_startups->end(); ++it) { - (*it)->HandleDidBecomeActive(application); - } - } -} - -// Call OpenUrl methods of registered instances of this class. -BOOL InvitesIosStartup::OpenUrl(UIApplication *application, NSURL *url, - NSString *sourceApplication, id annotation) { - if (s_invites_ios_startups) { - for (auto it = s_invites_ios_startups->begin(); it != s_invites_ios_startups->end(); ++it) { - if ((*it)->HandleOpenUrl(application, url, sourceApplication, annotation)) return YES; - } - } - return NO; -} - -BOOL InvitesIosStartup::OpenUrl(UIApplication *application, NSURL *url, - NSDictionary *options) { - if (s_invites_ios_startups) { - for (auto it = s_invites_ios_startups->begin(); it != s_invites_ios_startups->end(); ++it) { - if ((*it)->HandleOpenUrl(application, url, options)) return YES; - } - } - return NO; -} - -// Call ContinueUserActivity methods of registered instances of this class. -BOOL InvitesIosStartup::ContinueUserActivity(UIApplication *application, - NSUserActivity *userActivity, - void (^restorationHandler)(NSArray *)) { - if (s_invites_ios_startups) { - for (auto it = s_invites_ios_startups->begin(); it != s_invites_ios_startups->end(); ++it) { - if ((*it)->HandleContinueUserActivity(application, userActivity, restorationHandler)) { - return YES; - } - } - } - return NO; -} - -} // namespace internal - -} // namespace invites -} // namespace firebase - -// Category for UIApplication that is used to hook methods in all classes. Category +load() methods -// are called after all class load methods in each Mach-O (see call_load_methods() in -// http://www.opensource.apple.com/source/objc4/objc4-274/runtime/objc-runtime.m) -@implementation UIApplication (FIRFBI) -+ (void)load { - // C++ constructors may not be called yet so call NSLog rather than LogDebug. - NSLog(@"Loading UIApplication category for Firebase App"); - ::firebase::util::RunOnAppDelegateClasses(^(Class clazz) { - ::firebase::invites::HookAppDelegateMethods(clazz); - }); -} -@end diff --git a/app/src/invites/ios/invites_receiver_internal_ios.h b/app/src/invites/ios/invites_receiver_internal_ios.h deleted file mode 100644 index a1f825a213..0000000000 --- a/app/src/invites/ios/invites_receiver_internal_ios.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Internal header file for iOS Firebase invites sending functionality. - -#ifndef FIREBASE_APP_SRC_INVITES_IOS_INVITES_RECEIVER_INTERNAL_IOS_H_ -#define FIREBASE_APP_SRC_INVITES_IOS_INVITES_RECEIVER_INTERNAL_IOS_H_ - -#include - -#include "app/src/invites/invites_receiver_internal.h" - -#ifdef __OBJC__ -#include -#endif // __OBJC__ - -namespace firebase { -class App; -class Mutex; - -namespace invites { -namespace internal { - -// An internal class that performs the iOS-specific parts of receiving app -// invites and deep links. Because of the way iOS App Invites are implmented in -// the original library, the bulk of the work is done in the SetLaunchUrl() -// method. -// -// The general sequence of events when there's an incoming invite/deep link is: -// -// 1. SetLaunchUrl initializes and calls the dynamic links -// service to check for a deep link. -// -// 2. The dynamic links service, finding a link for the user, calls -// SetOpenUrl, passing in a special link that the app invites library will -// parse, which SetOpenUrl saves until later. -// -// 3. PerformFetch() checks the saved URL once it's present. If it matches the -// special format that the invites/DDL library uses, it parses out an invitation -// ID and/or deep link URL from it. -class InvitesReceiverInternalIos : public InvitesReceiverInternal { - public: - // Registers the startup class associated with this module. - // This can be used from a static object to ensure registration occurs before - // main(). - class StartupRegistration { - public: - // id must be valid for the lifetime of this class. - StartupRegistration(const char* id) : identifier_(id) { - InvitesReceiverInternalIos::RegisterStartup(this); - } - - // Identifier used to debug this object. - const char* identifier() const { return identifier_; } - - private: - const char* identifier_; - }; - - // Used to receive link data from Callbacks::FinishFetch() so that the - // InvitesReceiverInternalIos::Callbacks implementation can handle the - // URL link before InvitesReceiverInternalIos falls back to it's default - // behavior. - struct LinkInfo { - LinkInfo() : match_strength(kLinkMatchStrengthNoMatch) {} - - // ID of the invite derived from a URL link. - std::string invite_id; - // Deep link derived from a URL link. - std::string deep_link; - // How strong the match is. - InternalLinkMatchStrength match_strength; - }; - -#ifdef __OBJC__ - // Class used by the invites API to hook operations performed by the receiver. - class Callbacks { - public: - virtual ~Callbacks() {} - - // Used by Invites to complete Google Sign-in when sending an invite. - virtual bool OpenUrl(NSURL* url, NSString* source_application, - id annotation) = 0; - - // Called when a URL link (vs. universal link) is being processed by - // InvitesReceiverInternalIos::FinishFetch(). Dynamic link processing - // stops if this returns true. - virtual bool FinishFetch(NSURL* url, NSString* source_application, - id annotation, LinkInfo* link_info) = 0; - - // Called from InvitesReceiverInternalIos::PerformConvertInvitation() to - // convert an invite. - virtual void PerformConvertInvitation(const char* invitation_id) = 0; - }; -#else - // This header is also included by plain C++. - class Callbacks; -#endif // __OBJC__ - - // Work around a bug where null deep links cause Android clients to fail. - // TODO(jsimantov): Remove this constant when b/27612427 is fixed. - static const char* const kNullDeepLinkUrl; - - InvitesReceiverInternalIos(const ::firebase::App& app); - virtual ~InvitesReceiverInternalIos(); - - // This function consumes the URL previously set by open_url_. - virtual bool PerformFetch(); - - virtual bool PerformConvertInvitation(const char* invitation_id); - -#ifdef __OBJC__ - static void SetLaunchOptions(NSDictionary* launch_options); - static BOOL OpenUrl(NSURL* url, NSString* source_application, id annotation); - static BOOL OpenUniversalLink(NSURL* url); -#endif // __OBJC__ - - // Configure library specific callbacks, see Callbacks class for more - // information. - static void SetCallbacks(Callbacks* callbacks); - - // Register the component that handles app delegate callbacks. - static void RegisterStartup(StartupRegistration* registration); - - private: - void FinishFetch(); - - Mutex callback_mutex_; // Acquired when PerformFetch starts. - // Released after ReceivedInviteCallback is called. - bool fetch_in_progress_; // Whether a fetch is currently in progress. - Mutex fetch_mutex_; // Protects fetch_in_progress_. -}; - -} // namespace internal -} // namespace invites -} // namespace firebase - -#endif // FIREBASE_APP_SRC_INVITES_IOS_INVITES_RECEIVER_INTERNAL_IOS_H_ diff --git a/app/src/invites/ios/invites_receiver_internal_ios.mm b/app/src/invites/ios/invites_receiver_internal_ios.mm deleted file mode 100644 index 33550324f6..0000000000 --- a/app/src/invites/ios/invites_receiver_internal_ios.mm +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "app/src/invites/ios/invites_receiver_internal_ios.h" - -#include -#include -#include -#include - -#include "app/src/assert.h" -#include "app/src/include/firebase/app.h" -#include "app/src/include/firebase/internal/mutex.h" -#include "app/src/invites/invites_receiver_internal.h" -#include "app/src/invites/ios/invites_ios_startup.h" -#include "app/src/log.h" -#include "app/src/util_ios.h" - -#include "FIRDynamicLink.h" -#include "FIRDynamicLinks.h" - -// We need access to the inviteId method of FIRDynamicLink. This is not in the -// public API yet, but will be added in a future release. -@interface FIRDynamicLink () -- (nullable NSString *)inviteId; -@end - -namespace firebase { -namespace invites { -namespace internal { - -// When fetching invites, we will time out after kFetchCheckUrlTimeoutSeconds. -const float kFetchCheckUrlTimeoutSeconds = 300.0f; -// When fetching invites, how often to check if the URL has been set. -const float kFetchCheckUrlInitialIntervalSeconds = 0.2f; -// Amount to increase polling interval per iteration. -const float kFetchCheckUrlIntervalIncreaseSeconds = 0.2f; - -enum LinkType { kLinkTypeNone, kLinkTypeUrl, kLinkTypeUniversal }; - -// Fetch dynamic link / invite using the currently instanced receiver object. -// Do nothing if a receiver isn't available. -static void FetchDynamicLink(); - -class InvitesIosStartupImpl : public InvitesIosStartup { - public: - explicit InvitesIosStartupImpl(int priority) : InvitesIosStartup(priority) {} - virtual ~InvitesIosStartupImpl() {} - - protected: - void HandleDidBecomeActive(UIApplication *application) override { - LogDebug("HandleDidBecomeActive 0x%08x", - static_cast(reinterpret_cast(application))); - FetchDynamicLink(); - } - - BOOL HandleOpenUrl(UIApplication *application, NSURL *url, - NSString *sourceApplication, id annotation) override { - LogDebug("HandleOpenUrl %s %s", url ? url.absoluteString.UTF8String : "(null)", - sourceApplication ? sourceApplication.UTF8String : "(null)"); - return InvitesReceiverInternalIos::OpenUrl( - url, sourceApplication, annotation) != NO; - } - - BOOL HandleOpenUrl(UIApplication *application, NSURL *url, - NSDictionary *options) override { - NSString *sourceApplication = options[UIApplicationOpenURLOptionsSourceApplicationKey]; - id annotation = options[UIApplicationOpenURLOptionsAnnotationKey]; - LogDebug("HandleOpenUrl(new) %s %s", url ? url.absoluteString.UTF8String : "(null)", - sourceApplication ? sourceApplication.UTF8String : "(null)"); - return InvitesReceiverInternalIos::OpenUrl( - url, sourceApplication, annotation) != NO; - } - - BOOL HandleContinueUserActivity( - UIApplication *application, NSUserActivity *userActivity, - void (^restorationHandler)(NSArray *)) override { - LogDebug("ContinueUserActivity %s", userActivity && userActivity.webpageURL ? - userActivity.webpageURL.absoluteString.UTF8String : "(null)"); - return userActivity ? - InvitesReceiverInternalIos::OpenUniversalLink(userActivity.webpageURL) != NO - : false; - } -}; - -static LinkType g_got_link_type = kLinkTypeNone; -static NSURL *g_open_url; -static NSString *g_source_application; -static id g_annotation = nil; -// Amount of time elapsed (in seconds) since the dynamic link URL poller started. -static float g_fetch_timer = 0.0f; -// Amount of time (in seconds) to wait between polling the dynamic link URL. -static float g_fetch_poll_interval = 0.0f; - -// Instance of this class. This is used to execute dynamic link fetches from swizzled methods of -// the app delegate. -static InvitesReceiverInternalIos* g_invites_receiver = nullptr; - -// Miscellaneous hooks that are overriden by the invites library if it's initialized. -static InvitesReceiverInternalIos::Callbacks* g_callbacks = nullptr; - -static InvitesIosStartupImpl g_ios_startup_impl(0); - -// Mutex for the static stuff. -static ::firebase::Mutex g_static_mutex; - -// Fetch dynamic link / invite using the currently instanced receiver object. -// Do nothing if a receiver isn't available. -static void FetchDynamicLink() { - // Spin up a thread to perform a fetch call, because the underlying Fetch - // call can potentially end up blocking if another callback is happening, - // and we don't want to delay the startup. - MutexLock lock(g_static_mutex); - if (g_invites_receiver) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), - ^{ - MutexLock lock(g_static_mutex); - if (g_invites_receiver) g_invites_receiver->Fetch(); - }); - } -} - -// Register the component that handles app delegate callbacks. -void InvitesReceiverInternalIos::RegisterStartup(StartupRegistration *registration) { - firebase::LogDebug("Registered dynamic links handler %s", registration->identifier()); - g_ios_startup_impl.Register(); -} - - -// TODO(jsimantov): Remove this constant when b/27612427 is fixed. -const char* const InvitesReceiverInternalIos::kNullDeepLinkUrl = "file:///dev/null"; - -BOOL InvitesReceiverInternalIos::OpenUrl(NSURL *url, NSString *source_application, id annotation) { - LogDebug("OpenURL(%s, %s, %s)", url.description.UTF8String, - source_application.description.UTF8String, [annotation description].UTF8String); - MutexLock lock(g_static_mutex); - if (g_callbacks && g_callbacks->OpenUrl(url, source_application, annotation)) { - return YES; - } - g_open_url = url; - g_source_application = source_application; - g_annotation = annotation; - g_got_link_type = kLinkTypeUrl; - FetchDynamicLink(); - return YES; // We are potentially handling this URL. -} - -BOOL InvitesReceiverInternalIos::OpenUniversalLink(NSURL *universal_link) { - LogDebug("OpenUniversalLink(%s)", universal_link.description.UTF8String); - MutexLock lock(g_static_mutex); - g_open_url = universal_link; - g_source_application = nil; - g_annotation = nil; - g_got_link_type = kLinkTypeUniversal; - FetchDynamicLink(); - return YES; // We are potentially handling this URL. -} - -InvitesReceiverInternalIos::InvitesReceiverInternalIos( - const ::firebase::App &app) - : InvitesReceiverInternal(app), - callback_mutex_(Mutex::kModeNonRecursive), - fetch_in_progress_(false) { - assert(!g_invites_receiver); - g_invites_receiver = this; - g_ios_startup_impl.Register(); - -} - -InvitesReceiverInternalIos::~InvitesReceiverInternalIos() { - { - MutexLock lock(fetch_mutex_); - fetch_in_progress_ = false; - } - { - MutexLock lock(g_static_mutex); - g_invites_receiver = nullptr; - } - { - // Wait for any pending callbacks to finish. - MutexLock lock(callback_mutex_); - } - g_ios_startup_impl.Unregister(); -} - -bool InvitesReceiverInternalIos::PerformFetch() { - { - MutexLock lock(g_static_mutex); - g_fetch_timer = 0.0f; - g_fetch_poll_interval = kFetchCheckUrlInitialIntervalSeconds; - } - { - MutexLock lock(fetch_mutex_); - if (fetch_in_progress_) return true; - fetch_in_progress_ = true; - } - callback_mutex_.Acquire(); // Released by FinishFetch() when the fetch is complete. - std::string url; - MutexLock lock(g_static_mutex); - // Check if g_open_url is set. When the app starts, g_open_url will be null while - // checkForPendingDynamicLink executes, and then it will receive a special URL parsed by - // [FIRInvite handleURL], whether or not there is an app invite or deep link. This means there - // will be a short delay the first time we check for invites/deep links when the app starts. - if (g_open_url != nil) { - // Finish fetching now. - FinishFetch(); // Releases callback_mutex_. - } else { - // Spin up a thread to check on the URL. - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - // Check if we have received a URL yet. We should get one approx a quarter to half second - // after the app starts. We'll check a few times a second, and after a few seconds we give up - // and time out. - while (true) { - float current_interval; - { - MutexLock lock(g_static_mutex); - if (g_fetch_timer >= kFetchCheckUrlTimeoutSeconds) break; - g_fetch_timer += g_fetch_poll_interval; - current_interval = g_fetch_poll_interval; - g_fetch_poll_interval += kFetchCheckUrlIntervalIncreaseSeconds; - } - [NSThread sleepForTimeInterval:current_interval]; - { - MutexLock fetch_lock(fetch_mutex_); - if (!fetch_in_progress_) break; // Time out immediately. - } - bool link_ready = false; - { - MutexLock static_lock(g_static_mutex); - link_ready = g_open_url != nil; - } - if (link_ready) { - FinishFetch(); // Releases callback_mutex_. - return; - } - } - LogDebug("Timed out waiting for a link (waited %.2f seconds).", kFetchCheckUrlTimeoutSeconds); - // Timed out waiting to receive the invite. Unfortunately, this happens in the Invites library - // in certain cases. We have to consider that as just meaning there is no invite or deep link. - ReceivedInviteCallback("", "", kLinkMatchStrengthNoMatch, 0, ""); - callback_mutex_.Release(); - }); - } - return true; -} - -static internal::InternalLinkMatchStrength MatchTypeToLinkStrength(FIRDLMatchType match_type) { - switch (match_type) { - case FIRDLMatchTypeNone: - return internal::kLinkMatchStrengthNoMatch; - case FIRDLMatchTypeWeak: - return internal::kLinkMatchStrengthWeakMatch; - case FIRDLMatchTypeDefault: - return internal::kLinkMatchStrengthStrongMatch; - case FIRDLMatchTypeUnique: - return internal::kLinkMatchStrengthPerfectMatch; - } -} - -void InvitesReceiverInternalIos::FinishFetch() { - NSURL *url; - NSString *source_application; - id annotation; - LinkType link_type; - { - MutexLock lock(g_static_mutex); - FIREBASE_ASSERT(g_open_url != nil); - // Consume the URL. - url = g_open_url; - g_open_url = nil; - source_application = g_source_application; - g_source_application = nil; - annotation = g_annotation ? g_annotation : @{}; // handleURL fails on nil, use empty instead. - g_annotation = nil; - link_type = g_got_link_type; - g_got_link_type = kLinkTypeNone; - } - - if (link_type == kLinkTypeUrl) { - LogDebug("URL link %s", url.absoluteString.UTF8String); - // Regular URL, handle it synchronously. - bool processed_link = false; - LinkInfo link_info; - { - MutexLock lock(g_static_mutex); - processed_link = g_callbacks && g_callbacks->FinishFetch(url, source_application, annotation, - &link_info); - } - - int error_code = 0; - const char* error_string = ""; - if (!processed_link) { - // If FIRInvites couldn't get a link, check via FIRDynamicLinks instead (required for iOS 8). - FIRDynamicLink *dynamicLink = - [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url]; - - if (dynamicLink) { - // Got a FIRDynamicLink. It may or may not have an inviteId, but it will have a link. - // TODO(jsimantov): when FIRDynamicLink has metadata implemented, switch inviteId to use - // that. - NSString *inviteId = [dynamicLink inviteId]; - if (inviteId) link_info.invite_id = inviteId.UTF8String; - if (dynamicLink.url) link_info.deep_link = [dynamicLink.url absoluteString].UTF8String; - // TODO(jsimantov): Remove this workaround when b/27612427 is fixed. - if (link_info.deep_link == InvitesReceiverInternalIos::kNullDeepLinkUrl) { - link_info.deep_link = ""; - } - link_info.match_strength = MatchTypeToLinkStrength(dynamicLink.matchType); - } else { - LogWarning("Failed to process %s", url.absoluteString.UTF8String); - error_string = "Unable to retrieve link"; - error_code = 1; - } - } - ReceivedInviteCallback(link_info.invite_id, link_info.deep_link, link_info.match_strength, - error_code, error_string); - } else if (link_type == kLinkTypeUniversal) { - LogDebug("Universal link %s", url.absoluteString.UTF8String); - // Keep a strong reference to the FIRDynamicLinks singleton in the completion block until - // the block is complete. - __block FIRDynamicLinks* dynamic_links_reference = [FIRDynamicLinks dynamicLinks]; - // iOS 9+ Universal Link, handle asynchronously. (dynamic links only) - BOOL handled = [dynamic_links_reference handleUniversalLink:url - completion:^( - FIRDynamicLink *_Nullable dynamic_link, - NSError *_Nullable error) { - MutexLock lock(g_static_mutex); - dynamic_links_reference = nil; - auto receiver = g_invites_receiver; - if (receiver) { - int error_code = 1; /* firebase::dynamic_links::kErrorCodeFailed */ - std::string error_string = "Unknown error occurred."; - if (dynamic_link) { - std::string invite_id = util::NSStringToString(dynamic_link.inviteId); - std::string url_string = util::NSStringToString( - dynamic_link.url.absoluteString); - if (!url_string.empty() || !invite_id.empty()) { - receiver->ReceivedInviteCallback( - invite_id, url_string, MatchTypeToLinkStrength(dynamic_link.matchType), - 0, ""); - return; - } - } - if (error) { - std::string error_description = - util::NSStringToString(error.localizedDescription); - if (!error_description.empty()) error_string = error_description; - if (error.code) error_code = static_cast(error.code); - } else { - error_string = "The short dynamic link references a scheme that does not " - "match this application's bundle ID."; - } - receiver->ReceivedInviteCallback("", "", kLinkMatchStrengthNoMatch, error_code, - error_string); - } - }]; - if (!handled) { - // Link wasn't handled, complete with no received link. - ReceivedInviteCallback("", "", kLinkMatchStrengthNoMatch, 0, ""); - } - } - { - MutexLock lock(fetch_mutex_); - fetch_in_progress_ = false; - } - callback_mutex_.Release(); -} - -bool InvitesReceiverInternalIos::PerformConvertInvitation(const char* invitation_id) { - { - MutexLock lock(g_static_mutex); - if (g_callbacks) g_callbacks->PerformConvertInvitation(invitation_id); - } - ConvertedInviteCallback(invitation_id, 0, ""); - return true; -} - -void InvitesReceiverInternalIos::SetCallbacks( - InvitesReceiverInternalIos::Callbacks* callbacks) { - MutexLock lock(g_static_mutex); - g_callbacks = callbacks; -} - - -} // namespace internal -} // namespace invites -} // namespace firebase diff --git a/app/src/invites/receiver_interface.h b/app/src/invites/receiver_interface.h deleted file mode 100644 index da070ab239..0000000000 --- a/app/src/invites/receiver_interface.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FIREBASE_APP_SRC_INVITES_RECEIVER_INTERFACE_H_ -#define FIREBASE_APP_SRC_INVITES_RECEIVER_INTERFACE_H_ - -#include - -namespace firebase { -namespace invites { - -namespace internal { - -/// @brief Enum describing the strength of a dynamic links match. -/// -/// This version is only used internally, and is not exposed to the user. The -/// dynamic links and invites libraries both mirror this for a different version -/// that the dev can use. -enum InternalLinkMatchStrength { - /// No match has been achieved - kLinkMatchStrengthNoMatch = 0, - - /// The match between the Dynamic Link and device is not perfect. You should - /// not reveal any personal information related to the Dynamic Link. - kLinkMatchStrengthWeakMatch, - - /// The match between the Dynamic Link and this device has a high confidence, - /// but there is a small possibility of error. - kLinkMatchStrengthStrongMatch, - - /// The match between the Dynamic Link and the device is exact. You may - /// safely - /// reveal any personal information related to this Dynamic Link. - kLinkMatchStrengthPerfectMatch -}; - -class ReceiverInterface { - public: - virtual ~ReceiverInterface() {} - - // Callback called when an invite is received. If an error occurred, - // result_code should be non-zero. Otherwise, either invitation_id should be - // set, or deep_link_url should be set, or both. - virtual void ReceivedInviteCallback(const std::string& invitation_id, - const std::string& deep_link_url, - InternalLinkMatchStrength match_strength, - int result_code, - const std::string& error_message) = 0; -}; - -} // namespace internal -} // namespace invites -} // namespace firebase - -#endif // FIREBASE_APP_SRC_INVITES_RECEIVER_INTERFACE_H_ diff --git a/app/src/invites/sender_receiver_interface.h b/app/src/invites/sender_receiver_interface.h deleted file mode 100644 index ea83faa16e..0000000000 --- a/app/src/invites/sender_receiver_interface.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FIREBASE_APP_SRC_INVITES_SENDER_RECEIVER_INTERFACE_H_ -#define FIREBASE_APP_SRC_INVITES_SENDER_RECEIVER_INTERFACE_H_ - -#include -#include - -#include "app/src/invites/receiver_interface.h" - -namespace firebase { -namespace invites { -namespace internal { - -// Called by AndroidHelper when operations complete. -// This is due to AndroidHelper implementing both invite send and dynamic link -// receive operations on Android. -// This interface is not implemented on iOS as the dynamic link receive logic -// is completely separate from the invite sending logic. -class SenderReceiverInterface : public ReceiverInterface { - public: - SenderReceiverInterface() {} - virtual ~SenderReceiverInterface() {} - - // Called when an invite has been sent. - virtual void SentInviteCallback( - const std::vector& invitation_ids, int result_code, - const std::string& error_message) = 0; - - // Callback called when an invite conversion occurs. If an error occurred, - // result_code will be non-zero. Otherwise, the conversion was successful. - virtual void ConvertedInviteCallback(const std::string& invitation_id, - int result_code, - std::string error_message) = 0; -}; - -} // namespace internal -} // namespace invites -} // namespace firebase - -#endif // FIREBASE_APP_SRC_INVITES_SENDER_RECEIVER_INTERFACE_H_ diff --git a/app/src/invites/stub/invites_receiver_internal_stub.cc b/app/src/invites/stub/invites_receiver_internal_stub.cc deleted file mode 100644 index 58156b0680..0000000000 --- a/app/src/invites/stub/invites_receiver_internal_stub.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "app/src/invites/stub/invites_receiver_internal_stub.h" - -namespace firebase { -namespace invites { -namespace internal { - -InvitesReceiverInternalStub::~InvitesReceiverInternalStub() {} - -bool InvitesReceiverInternalStub::PerformFetch() { return true; } - -bool InvitesReceiverInternalStub::PerformConvertInvitation( - const char* /* unused */) { - return true; -} - -} // namespace internal -} // namespace invites -} // namespace firebase diff --git a/app/src/invites/stub/invites_receiver_internal_stub.h b/app/src/invites/stub/invites_receiver_internal_stub.h deleted file mode 100644 index 763139c105..0000000000 --- a/app/src/invites/stub/invites_receiver_internal_stub.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2017 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FIREBASE_APP_SRC_INVITES_STUB_INVITES_RECEIVER_INTERNAL_STUB_H_ -#define FIREBASE_APP_SRC_INVITES_STUB_INVITES_RECEIVER_INTERNAL_STUB_H_ - -#include "app/src/invites/invites_receiver_internal.h" - -namespace firebase { -class App; -namespace invites { -namespace internal { - -// Stub version of InvitesReceiverInternal, for use on desktop platforms. This -// version will simply not be able to fetch or convert invitations, and will -// return an error if you try. -class InvitesReceiverInternalStub : public InvitesReceiverInternal { - public: - explicit InvitesReceiverInternalStub(const ::firebase::App& app) - : InvitesReceiverInternal(app) {} - virtual ~InvitesReceiverInternalStub(); // NOLINT - virtual bool PerformFetch(); // NOLINT - virtual bool PerformConvertInvitation(const char* /* unused */); // NOLINT -}; - -} // namespace internal -} // namespace invites -} // namespace firebase - -#endif // FIREBASE_APP_SRC_INVITES_STUB_INVITES_RECEIVER_INTERNAL_STUB_H_ diff --git a/build_scripts/ios/build.sh b/build_scripts/ios/build.sh index c466d35af7..8b8fb2fab5 100755 --- a/build_scripts/ios/build.sh +++ b/build_scripts/ios/build.sh @@ -27,7 +27,7 @@ readonly SUPPORTED_PLATFORMS=(device simulator) readonly SUPPORTED_ARCHITECTURES=(arm64 x86_64) readonly DEVICE_ARCHITECTURES=(arm64) readonly SIMULATOR_ARCHITECTURES=(arm64 x86_64) -readonly SUPPORTED_TARGETS=(firebase_analytics firebase_auth firebase_app_check firebase_database firebase_dynamic_links firebase_firestore firebase_functions firebase_gma firebase_installations firebase_messaging firebase_remote_config firebase_storage firebase_ump) +readonly SUPPORTED_TARGETS=(firebase_analytics firebase_auth firebase_app_check firebase_database firebase_firestore firebase_functions firebase_gma firebase_installations firebase_messaging firebase_remote_config firebase_storage firebase_ump) # build default value buildpath="ios_build" diff --git a/build_scripts/packaging.conf b/build_scripts/packaging.conf index 8f1ee6f401..b2e40da1c1 100644 --- a/build_scripts/packaging.conf +++ b/build_scripts/packaging.conf @@ -2,5 +2,5 @@ # List of all Firebase products to include in the binary SDK package. readonly -a product_list=(analytics app app_check auth database -dynamic_links firestore functions gma installations messaging +firestore functions gma installations messaging remote_config storage ump) diff --git a/dynamic_links/CMakeLists.txt b/dynamic_links/CMakeLists.txt deleted file mode 100644 index 01283f3f38..0000000000 --- a/dynamic_links/CMakeLists.txt +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2019 Google -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# CMake file for the firebase_dynamic_links library - -# Common source files used by all platforms -set(common_SRCS - src/common.cc - src/common.h - src/listener.cc) - -# Source files used by the Android implementation. -set(android_SRCS - src/dynamic_links_android.cc) - -# Source files used by the iOS implementation. -set(ios_SRCS - src/dynamic_links_ios.mm) - -# Source files used by the stub implementation. -set(stub_SRCS - src/dynamic_links_stub.cc) - -if(ANDROID) - set(dynamic_links_platform_SRCS - "${android_SRCS}") -elseif(IOS) - set(dynamic_links_platform_SRCS - "${ios_SRCS}") -else() - set(dynamic_links_platform_SRCS - "${stub_SRCS}") -endif() - -add_library(firebase_dynamic_links STATIC - ${common_SRCS} - ${dynamic_links_platform_SRCS}) - -set_property(TARGET firebase_dynamic_links PROPERTY FOLDER "Firebase Cpp") - -# Set up the dependency on Firebase App. -target_link_libraries(firebase_dynamic_links - PUBLIC firebase_app) -# Public headers all refer to each other relative to the src/include directory, -# while private headers are relative to the entire C++ SDK directory. -target_include_directories(firebase_dynamic_links - PUBLIC - ${CMAKE_CURRENT_LIST_DIR}/src/include - PRIVATE - ${FIREBASE_CPP_SDK_ROOT_DIR} -) -target_compile_definitions(firebase_dynamic_links - PRIVATE - -DINTERNAL_EXPERIMENTAL=1 -) -# Automatically include headers that might not be declared. -if(MSVC) - add_definitions(/FI"assert.h" /FI"string.h" /FI"stdint.h") -else() - add_definitions(-include assert.h -include string.h) -endif() - -if(ANDROID) - firebase_cpp_proguard_file(dynamic_links) -elseif(IOS) - # Enable Automatic Reference Counting (ARC) and Bitcode. - target_compile_options(firebase_dynamic_links - PUBLIC "-fobjc-arc" "-fembed-bitcode") - target_link_libraries(firebase_dynamic_links - PUBLIC "-fembed-bitcode") - - setup_pod_headers( - firebase_dynamic_links - POD_NAMES - FirebaseDynamicLinks - ) - - if (FIREBASE_XCODE_TARGET_FORMAT STREQUAL "frameworks") - set_target_properties(firebase_dynamic_links PROPERTIES - FRAMEWORK TRUE - ) - endif() -endif() - -cpp_pack_library(firebase_dynamic_links "") -cpp_pack_public_headers() diff --git a/dynamic_links/build.gradle b/dynamic_links/build.gradle deleted file mode 100644 index 6fd8088c25..0000000000 --- a/dynamic_links/build.gradle +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -buildscript { - repositories { - google() - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' - } -} -allprojects { - repositories { - google() - mavenCentral() - } -} - -apply plugin: 'com.android.library' - -android { - compileSdkVersion 34 - ndkPath System.getenv('ANDROID_NDK_HOME') - buildToolsVersion '32.0.0' - - sourceSets { - main { - manifest.srcFile '../android_build_files/AndroidManifest.xml' - } - } - - externalNativeBuild { - cmake { - path '../CMakeLists.txt' - } - } - - defaultConfig { - minSdkVersion 23 - targetSdkVersion 34 - versionCode 1 - versionName "1.0" - - buildTypes { - release { - minifyEnabled false - } - } - - externalNativeBuild { - cmake { - targets 'firebase_dynamic_links' - // Args are: Re-use app library prebuilt by app gradle project. - // Don't configure all the cmake subprojects. - // Only include needed project. - arguments '-DFIREBASE_CPP_USE_PRIOR_GRADLE_BUILD=ON', - '-DFIREBASE_INCLUDE_LIBRARY_DEFAULT=OFF', - '-DFIREBASE_INCLUDE_DYNAMIC_LINKS=ON' - } - } - } - - lintOptions { - abortOnError false - } -} - -dependencies { - implementation project(':app') -} -apply from: "$rootDir/android_build_files/android_abis.gradle" -apply from: "$rootDir/android_build_files/generate_proguard.gradle" -project.afterEvaluate { - generateProguardFile('dynamic_links') - preBuild.dependsOn(':app:build') - project.tasks.withType(com.android.build.gradle.internal.tasks.CheckAarMetadataTask) { - enabled = false - } -} diff --git a/dynamic_links/integration_test/AndroidManifest.xml b/dynamic_links/integration_test/AndroidManifest.xml deleted file mode 100644 index d737ea3ec6..0000000000 --- a/dynamic_links/integration_test/AndroidManifest.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/dynamic_links/integration_test/CMakeLists.txt b/dynamic_links/integration_test/CMakeLists.txt deleted file mode 100644 index 5286ceba8c..0000000000 --- a/dynamic_links/integration_test/CMakeLists.txt +++ /dev/null @@ -1,242 +0,0 @@ -# Copyright 2020 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Cmake file for a single C++ integration test build. - -cmake_minimum_required(VERSION 2.8) - -find_program(FIREBASE_PYTHON_EXECUTABLE - NAMES python3 python - DOC "The Python interpreter to use, such as one from a venv" - REQUIRED -) - -# User settings for Firebase integration tests. -# Path to Firebase SDK. -# Try to read the path to the Firebase C++ SDK from an environment variable. -if (NOT "$ENV{FIREBASE_CPP_SDK_DIR}" STREQUAL "") - set(DEFAULT_FIREBASE_CPP_SDK_DIR "$ENV{FIREBASE_CPP_SDK_DIR}") -else() - if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/../../cpp_sdk_version.json") - set(DEFAULT_FIREBASE_CPP_SDK_DIR "${CMAKE_CURRENT_LIST_DIR}/../..") - else() - set(DEFAULT_FIREBASE_CPP_SDK_DIR "firebase_cpp_sdk") - endif() -endif() -if ("${FIREBASE_CPP_SDK_DIR}" STREQUAL "") - set(FIREBASE_CPP_SDK_DIR ${DEFAULT_FIREBASE_CPP_SDK_DIR}) -endif() -if(NOT EXISTS ${FIREBASE_CPP_SDK_DIR}) - message(FATAL_ERROR "The Firebase C++ SDK directory does not exist: ${FIREBASE_CPP_SDK_DIR}. See the readme.md for more information") -endif() - -# Copy all prerequisite files for integration tests to run. -if(NOT ANDROID) - if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/../../setup_integration_tests.py) - # If this is running from inside the SDK directory, run the setup script. - execute_process( - COMMAND - ${FIREBASE_PYTHON_EXECUTABLE} - "${CMAKE_CURRENT_LIST_DIR}/../../setup_integration_tests.py" - "${CMAKE_CURRENT_LIST_DIR}" - RESULT_VARIABLE - FIREBASE_PYTHON_EXECUTABLE_RESULT - ) - if(NOT FIREBASE_PYTHON_EXECUTABLE_RESULT EQUAL 0) - message(FATAL_ERROR "Failed to run setup_integration_tests.py") - endif() - endif() -endif() - -# Windows runtime mode, either MD or MT depending on whether you are using -# /MD or /MT. For more information see: -# https://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx -set(MSVC_RUNTIME_MODE MD) - -project(firebase_testapp) - -# Integration test source files. -set(FIREBASE_APP_FRAMEWORK_SRCS - src/app_framework.cc - src/app_framework.h -) - -set(FIREBASE_TEST_FRAMEWORK_SRCS - src/firebase_test_framework.h - src/firebase_test_framework.cc -) - -set(FIREBASE_INTEGRATION_TEST_SRCS - src/integration_test.cc -) - -# The include directory for the testapp. -include_directories(src) - -# Firebase C++ SDK requires C++14. -set (CMAKE_CXX_STANDARD 14) -set (CMAKE_CXX_STANDARD_REQUIRED YES) # Don't fall back to an earlier version. - -# Download and unpack googletest (and googlemock) at configure time -set(GOOGLETEST_ROOT ${CMAKE_CURRENT_LIST_DIR}/external/googletest) -# Note: Once googletest is downloaded once, it won't be updated or -# downloaded again unless you delete the "external/googletest" -# directory. -if (NOT EXISTS ${GOOGLETEST_ROOT}/src/googletest/src/gtest-all.cc) - configure_file(googletest.cmake - ${CMAKE_CURRENT_LIST_DIR}/external/googletest/CMakeLists.txt COPYONLY) - execute_process(COMMAND ${CMAKE_COMMAND} . - RESULT_VARIABLE result - WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/external/googletest ) - if(result) - message(FATAL_ERROR "CMake step for googletest failed: ${result}") - endif() - execute_process(COMMAND ${CMAKE_COMMAND} --build . - RESULT_VARIABLE result - WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/external/googletest ) - if(result) - message(FATAL_ERROR "Build step for googletest failed: ${result}") - endif() -endif() - -if(ANDROID) - # Build an Android application. - - # Source files used for the Android build. - set(FIREBASE_APP_FRAMEWORK_ANDROID_SRCS - src/android/android_app_framework.cc - ) - - # Source files used for the Android build. - set(FIREBASE_TEST_FRAMEWORK_ANDROID_SRCS - src/android/android_firebase_test_framework.cc - ) - - # Build native_app_glue as a static lib - add_library(native_app_glue STATIC - ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c) - - # Export ANativeActivity_onCreate(), - # Refer to: https://github.com/android-ndk/ndk/issues/381. - set(CMAKE_SHARED_LINKER_FLAGS - "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate") - - add_library(gtest STATIC - ${GOOGLETEST_ROOT}/src/googletest/src/gtest-all.cc) - target_include_directories(gtest - PRIVATE ${GOOGLETEST_ROOT}/src/googletest - PUBLIC ${GOOGLETEST_ROOT}/src/googletest/include) - add_library(gmock STATIC - ${GOOGLETEST_ROOT}/src/googlemock/src/gmock-all.cc) - target_include_directories(gmock - PRIVATE ${GOOGLETEST_ROOT}/src/googletest - PRIVATE ${GOOGLETEST_ROOT}/src/googlemock - PUBLIC ${GOOGLETEST_ROOT}/src/googletest/include - PUBLIC ${GOOGLETEST_ROOT}/src/googlemock/include) - - # Define the target as a shared library, as that is what gradle expects. - set(integration_test_target_name "android_integration_test_main") - add_library(${integration_test_target_name} SHARED - ${FIREBASE_APP_FRAMEWORK_SRCS} - ${FIREBASE_APP_FRAMEWORK_ANDROID_SRCS} - ${FIREBASE_INTEGRATION_TEST_SRCS} - ${FIREBASE_TEST_FRAMEWORK_SRCS} - ${FIREBASE_TEST_FRAMEWORK_ANDROID_SRCS} - ) - - target_include_directories(${integration_test_target_name} PRIVATE - ${ANDROID_NDK}/sources/android/native_app_glue) - - set(ADDITIONAL_LIBS log android atomic native_app_glue) -else() - # Build a desktop application. - add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) - - # Prevent overriding the parent project's compiler/linker - # settings on Windows - set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - - # Add googletest directly to our build. This defines - # the gtest and gtest_main targets. - add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/external/googletest/src - ${CMAKE_CURRENT_LIST_DIR}/external/googletest/build - EXCLUDE_FROM_ALL) - - # The gtest/gtest_main targets carry header search path - # dependencies automatically when using CMake 2.8.11 or - # later. Otherwise we have to add them here ourselves. - if (CMAKE_VERSION VERSION_LESS 2.8.11) - include_directories("${gtest_SOURCE_DIR}/include") - include_directories("${gmock_SOURCE_DIR}/include") - endif() - - # Windows runtime mode, either MD or MT depending on whether you are using - # /MD or /MT. For more information see: - # https://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx - set(MSVC_RUNTIME_MODE MD) - - # Platform abstraction layer for the desktop integration test. - set(FIREBASE_APP_FRAMEWORK_DESKTOP_SRCS - src/desktop/desktop_app_framework.cc - src/desktop/desktop_firebase_test_framework.cc - ) - - set(integration_test_target_name "integration_test") - add_executable(${integration_test_target_name} - ${FIREBASE_APP_FRAMEWORK_SRCS} - ${FIREBASE_APP_FRAMEWORK_DESKTOP_SRCS} - ${FIREBASE_TEST_FRAMEWORK_SRCS} - ${FIREBASE_INTEGRATION_TEST_SRCS} - ) - - if(APPLE) - set(ADDITIONAL_LIBS - gssapi_krb5 - pthread - "-framework CoreFoundation" - "-framework Foundation" - "-framework GSS" - "-framework Security" - ) - elseif(MSVC) - set(ADDITIONAL_LIBS advapi32 ws2_32 crypt32) - else() - set(ADDITIONAL_LIBS pthread) - endif() - - # If a config file is present, copy it into the binary location so that it's - # possible to create the default Firebase app. - set(FOUND_JSON_FILE FALSE) - foreach(config "google-services-desktop.json" "google-services.json") - if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${config}") - add_custom_command( - TARGET ${integration_test_target_name} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - "${CMAKE_CURRENT_LIST_DIR}/${config}" $) - set(FOUND_JSON_FILE TRUE) - break() - endif() - endforeach() - if(NOT FOUND_JSON_FILE) - message(WARNING "Failed to find either google-services-desktop.json or google-services.json. See the readme.md for more information.") - endif() -endif() - -# Add the Firebase libraries to the target using the function from the SDK. -add_subdirectory(${FIREBASE_CPP_SDK_DIR} bin/ EXCLUDE_FROM_ALL) -# Note that firebase_app needs to be last in the list. -set(firebase_libs firebase_dynamic_links firebase_app) -set(gtest_libs gtest gmock) -target_link_libraries(${integration_test_target_name} ${firebase_libs} - ${gtest_libs} ${ADDITIONAL_LIBS}) diff --git a/dynamic_links/integration_test/Images.xcassets/AppIcon.appiconset/Contents.json b/dynamic_links/integration_test/Images.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d8db8d65fd..0000000000 --- a/dynamic_links/integration_test/Images.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" - }, - { - "idiom" : "ios-marketing", - "size" : "1024x1024", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/dynamic_links/integration_test/Images.xcassets/LaunchImage.launchimage/Contents.json b/dynamic_links/integration_test/Images.xcassets/LaunchImage.launchimage/Contents.json deleted file mode 100644 index 6f870a4629..0000000000 --- a/dynamic_links/integration_test/Images.xcassets/LaunchImage.launchimage/Contents.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "images" : [ - { - "orientation" : "portrait", - "idiom" : "iphone", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "iphone", - "subtype" : "retina4", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "1x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "1x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/dynamic_links/integration_test/Info.plist b/dynamic_links/integration_test/Info.plist deleted file mode 100644 index 7b0cefa0bc..0000000000 --- a/dynamic_links/integration_test/Info.plist +++ /dev/null @@ -1,56 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleURLSchemes - - $(PRODUCT_BUNDLE_IDENTIFIER) - - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLName - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleURLSchemes - - $(PRODUCT_BUNDLE_IDENTIFIER) - - - - CFBundleTypeRole - Editor - CFBundleURLName - google - CFBundleURLSchemes - - REPLACE_WITH_REVERSED_CLIENT_ID - firebase-game-loop - - - - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - NSContactsUsageDescription - Invite others to use the app. - - diff --git a/dynamic_links/integration_test/LaunchScreen.storyboard b/dynamic_links/integration_test/LaunchScreen.storyboard deleted file mode 100644 index 673e0f7e68..0000000000 --- a/dynamic_links/integration_test/LaunchScreen.storyboard +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dynamic_links/integration_test/LibraryManifest.xml b/dynamic_links/integration_test/LibraryManifest.xml deleted file mode 100644 index 3cd768235d..0000000000 --- a/dynamic_links/integration_test/LibraryManifest.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - diff --git a/dynamic_links/integration_test/Podfile b/dynamic_links/integration_test/Podfile deleted file mode 100644 index d6a404cee9..0000000000 --- a/dynamic_links/integration_test/Podfile +++ /dev/null @@ -1,16 +0,0 @@ -source 'https://github.com/CocoaPods/Specs.git' -platform :ios, '13.0' -# Firebase Dynamic Links test application. -use_frameworks! :linkage => :static - -target 'integration_test' do - platform :ios, '13.0' - pod 'Firebase/DynamicLinks', '11.14.0' -end - -post_install do |installer| - # If this is running from inside the SDK directory, run the setup script. - system("if [[ -r ../../setup_integration_tests.py ]]; then python3 ../../setup_integration_tests.py .; fi") - system("python3 ./download_googletest.py") -end - diff --git a/dynamic_links/integration_test/build.gradle b/dynamic_links/integration_test/build.gradle deleted file mode 100644 index 65c65fc06b..0000000000 --- a/dynamic_links/integration_test/build.gradle +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Top-level build file where you can add configuration options common to all sub-projects/modules. -buildscript { - repositories { - mavenLocal() - maven { url 'https://maven.google.com' } - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' - // r8 on this version of the Android tools has a bug, - // so specify a different version to use. - classpath 'com.android.tools:r8:8.3.37' - classpath 'com.google.gms:google-services:4.4.1' - } -} - -allprojects { - repositories { - mavenLocal() - maven { url 'https://maven.google.com' } - mavenCentral() - } -} - -apply plugin: 'com.android.application' - -android { - compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 - } - compileSdkVersion 34 - ndkPath System.getenv('ANDROID_NDK_HOME') - buildToolsVersion '32.0.0' - - sourceSets { - main { - jniLibs.srcDirs = ['libs'] - manifest.srcFile 'AndroidManifest.xml' - java.srcDirs = ['src/android/java'] - res.srcDirs = ['res'] - } - } - - defaultConfig { - applicationId 'com.google.android.dynamiclinks.testapp' - minSdkVersion 23 - targetSdkVersion 34 - versionCode 1 - versionName '1.0' - externalNativeBuild.cmake { - arguments "-DFIREBASE_CPP_SDK_DIR=$gradle.firebase_cpp_sdk_dir" - } - } - externalNativeBuild.cmake { - path 'CMakeLists.txt' - } - buildTypes { - release { - minifyEnabled true - proguardFile getDefaultProguardFile('proguard-android.txt') - proguardFile file('proguard.pro') - } - } -} - -apply from: "$gradle.firebase_cpp_sdk_dir/Android/firebase_dependencies.gradle" -firebaseCpp.dependencies { - dynamicLinks -} - -apply plugin: 'com.google.gms.google-services' - -task copyIntegrationTestFiles(type:Exec) { - // If this is running form inside the SDK directory, run the setup script. - if (project.file('../../setup_integration_tests.py').exists()) { - commandLine 'python3', '../../setup_integration_tests.py', project.projectDir.toString() - } - else { - commandLine 'echo', '' - } -} - -build.dependsOn(copyIntegrationTestFiles) - -project.afterEvaluate { - project.tasks.withType(com.android.build.gradle.internal.tasks.CheckAarMetadataTask) { - enabled = false - } -} diff --git a/dynamic_links/integration_test/googletest.cmake b/dynamic_links/integration_test/googletest.cmake deleted file mode 100644 index 2261a3a7f6..0000000000 --- a/dynamic_links/integration_test/googletest.cmake +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Download GoogleTest from GitHub as an external project. -# Pin to 1.11.0 because we touch internal GoogleTest structures that could change in the future. - -# This CMake file is taken from: -# https://github.com/google/googletest/blob/master/googletest/README.md#incorporating-into-an-existing-cmake-project - -cmake_minimum_required(VERSION 2.8.2) - -project(googletest-download NONE) - -include(ExternalProject) -ExternalProject_Add(googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG "release-1.11.0" - SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/src" - BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/build" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" -) diff --git a/dynamic_links/integration_test/gradle.properties b/dynamic_links/integration_test/gradle.properties deleted file mode 100644 index ac891ac594..0000000000 --- a/dynamic_links/integration_test/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -android.useAndroidX = true -org.gradle.jvmargs=-Xmx2560m diff --git a/dynamic_links/integration_test/gradle/wrapper/gradle-wrapper.jar b/dynamic_links/integration_test/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 8c0fb64a8698b08ecc4158d828ca593c4928e9dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49896 zcmagFb986H(k`5d^NVfUwr$(C?M#x1ZQHiZiEVpg+jrjgoQrerx!>1o_ul)D>ebz~ zs=Mmxr&>W81QY-S1PKWQ%N-;H^tS;2*XwVA`dej1RRn1z<;3VgfE4~kaG`A%QSPsR z#ovnZe+tS9%1MfeDyz`RirvdjPRK~p(#^q2(^5@O&NM19EHdvN-A&StN>0g6QA^VN z0Gx%Gq#PD$QMRFzmK+utjS^Y1F0e8&u&^=w5K<;4Rz|i3A=o|IKLY+g`iK6vfr9?+ z-`>gmU&i?FGSL5&F?TXFu`&Js6h;15QFkXp2M1H9|Eq~bpov-GU(uz%mH0n55wUl- zv#~ccAz`F5wlQ>e_KlJS3@{)B?^v*EQM=IxLa&76^y51a((wq|2-`qON>+4dLc{Oo z51}}o^Zen(oAjxDK7b++9_Yg`67p$bPo3~BCpGM7uAWmvIhWc5Gi+gQZ|Pwa-Gll@<1xmcPy z|NZmu6m)g5Ftu~BG&Xdxclw7Cij{xbBMBn-LMII#Slp`AElb&2^Hw+w>(3crLH!;I zN+Vk$D+wP1#^!MDCiad@vM>H#6+`Ct#~6VHL4lzmy;lSdk>`z6)=>Wh15Q2)dQtGqvn0vJU@+(B5{MUc*qs4!T+V=q=wy)<6$~ z!G>e_4dN@lGeF_$q9`Ju6Ncb*x?O7=l{anm7Eahuj_6lA{*#Gv*TaJclevPVbbVYu z(NY?5q+xxbO6%g1xF0r@Ix8fJ~u)VRUp`S%&rN$&e!Od`~s+64J z5*)*WSi*i{k%JjMSIN#X;jC{HG$-^iX+5f5BGOIHWAl*%15Z#!xntpk($-EGKCzKa zT7{siZ9;4TICsWQ$pu&wKZQTCvpI$Xvzwxoi+XkkpeE&&kFb!B?h2hi%^YlXt|-@5 zHJ~%AN!g_^tmn1?HSm^|gCE#!GRtK2(L{9pL#hp0xh zME}|DB>(5)`iE7CM)&_+S}-Bslc#@B5W4_+k4Cp$l>iVyg$KP>CN?SVGZ(&02>iZK zB<^HP$g$Lq*L$BWd?2(F?-MUbNWTJVQdW7$#8a|k_30#vHAD1Z{c#p;bETk0VnU5A zBgLe2HFJ3032$G<`m*OB!KM$*sdM20jm)It5OSru@tXpK5LT>#8)N!*skNu1$TpIw zufjjdp#lyH5bZ%|Iuo|iu9vG1HrIVWLH>278xo>aVBkPN3V$~!=KnlXQ4eDqS7%E% zQ!z^$Q$b^6Q)g#cLpwur(|<0gWHo6A6jc;n`t(V9T;LzTAU{IAu*uEQ%Ort1k+Kn+f_N`9|bxYC+~Z1 zCC1UCWv*Orx$_@ydv9mIe(liLfOr7mhbV@tKw{6)q^1DH1nmvZ0cj215R<~&I<4S| zgnr;9Cdjqpz#o8i0CQjtl`}{c*P)aSdH|abxGdrR)-3z+02-eX(k*B)Uqv6~^nh** z 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/dynamic_links/integration_test/gradlew.bat b/dynamic_links/integration_test/gradlew.bat deleted file mode 100644 index 4ba75ee288..0000000000 --- a/dynamic_links/integration_test/gradlew.bat +++ /dev/null @@ -1,104 +0,0 @@ -@rem Copyright 2020 Google LLC -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem http://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/dynamic_links/integration_test/integration_test.entitlements b/dynamic_links/integration_test/integration_test.entitlements deleted file mode 100644 index f8adad53ee..0000000000 --- a/dynamic_links/integration_test/integration_test.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - application-identifier - $(AppIdentifierPrefix)$(CFBundleIdentifier) - com.apple.developer.associated-domains - - applinks:REPLACE_WITH_YOUR_URI_PREFIX - - - diff --git a/dynamic_links/integration_test/integration_test.xcodeproj/project.pbxproj b/dynamic_links/integration_test/integration_test.xcodeproj/project.pbxproj deleted file mode 100644 index 76cdf2d9af..0000000000 --- a/dynamic_links/integration_test/integration_test.xcodeproj/project.pbxproj +++ /dev/null @@ -1,377 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 520BC0391C869159008CFBC3 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 520BC0381C869159008CFBC3 /* GoogleService-Info.plist */; }; - 529226D61C85F68000C89379 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 529226D51C85F68000C89379 /* Foundation.framework */; }; - 529226D81C85F68000C89379 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 529226D71C85F68000C89379 /* CoreGraphics.framework */; }; - 529226DA1C85F68000C89379 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 529226D91C85F68000C89379 /* UIKit.framework */; }; - D603B7262819C8CA008A979F /* empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = D603B7252819C8CA008A979F /* empty.swift */; }; - D61C5F8E22BABA9C00A79141 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D61C5F8C22BABA9B00A79141 /* Images.xcassets */; }; - D61C5F9622BABAD200A79141 /* integration_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = D61C5F9222BABAD100A79141 /* integration_test.cc */; }; - D62CCBC022F367140099BE9F /* gmock-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = D62CCBBF22F367140099BE9F /* gmock-all.cc */; }; - D66B16871CE46E8900E5638A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D66B16861CE46E8900E5638A /* LaunchScreen.storyboard */; }; - D67D355822BABD2200292C1D /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = D67D355622BABD2100292C1D /* gtest-all.cc */; }; - D6C179E922CB322900C2651A /* ios_app_framework.mm in Sources */ = {isa = PBXBuildFile; fileRef = D6C179E722CB322900C2651A /* ios_app_framework.mm */; }; - D6C179EA22CB322900C2651A /* ios_firebase_test_framework.mm in Sources */ = {isa = PBXBuildFile; fileRef = D6C179E822CB322900C2651A /* ios_firebase_test_framework.mm */; }; - D6C179EE22CB323300C2651A /* firebase_test_framework.cc in Sources */ = {isa = PBXBuildFile; fileRef = D6C179EC22CB323300C2651A /* firebase_test_framework.cc */; }; - D6C179F022CB32A000C2651A /* app_framework.cc in Sources */ = {isa = PBXBuildFile; fileRef = D6C179EF22CB32A000C2651A /* app_framework.cc */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 520BC0381C869159008CFBC3 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 529226D21C85F68000C89379 /* integration_test.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = integration_test.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 529226D51C85F68000C89379 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 529226D71C85F68000C89379 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 529226D91C85F68000C89379 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 529226EE1C85F68000C89379 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; - D603B7252819C8CA008A979F /* empty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = empty.swift; path = src/empty.swift; sourceTree = ""; }; - D61C5F8C22BABA9B00A79141 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; - D61C5F8D22BABA9C00A79141 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - D61C5F9222BABAD100A79141 /* integration_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = integration_test.cc; path = src/integration_test.cc; sourceTree = ""; }; - D62CCBBF22F367140099BE9F /* gmock-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gmock-all.cc"; path = "external/googletest/src/googlemock/src/gmock-all.cc"; sourceTree = ""; }; - D62CCBC122F367320099BE9F /* gmock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gmock.h; path = external/googletest/src/googlemock/include/gmock/gmock.h; sourceTree = ""; }; - D66B16861CE46E8900E5638A /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; - D67D355622BABD2100292C1D /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gtest-all.cc"; path = "external/googletest/src/googletest/src/gtest-all.cc"; sourceTree = ""; }; - D67D355722BABD2100292C1D /* gtest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gtest.h; path = external/googletest/src/googletest/include/gtest/gtest.h; sourceTree = ""; }; - D6C179E722CB322900C2651A /* ios_app_framework.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ios_app_framework.mm; path = src/ios/ios_app_framework.mm; sourceTree = ""; }; - D6C179E822CB322900C2651A /* ios_firebase_test_framework.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ios_firebase_test_framework.mm; path = src/ios/ios_firebase_test_framework.mm; sourceTree = ""; }; - D6C179EB22CB323300C2651A /* firebase_test_framework.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = firebase_test_framework.h; path = src/firebase_test_framework.h; sourceTree = ""; }; - D6C179EC22CB323300C2651A /* firebase_test_framework.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = firebase_test_framework.cc; path = src/firebase_test_framework.cc; sourceTree = ""; }; - D6C179ED22CB323300C2651A /* app_framework.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = app_framework.h; path = src/app_framework.h; sourceTree = ""; }; - D6C179EF22CB32A000C2651A /* app_framework.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = app_framework.cc; path = src/app_framework.cc; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 529226CF1C85F68000C89379 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 529226D81C85F68000C89379 /* CoreGraphics.framework in Frameworks */, - 529226DA1C85F68000C89379 /* UIKit.framework in Frameworks */, - 529226D61C85F68000C89379 /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 529226C91C85F68000C89379 = { - isa = PBXGroup; - children = ( - D61C5F8C22BABA9B00A79141 /* Images.xcassets */, - D61C5F8D22BABA9C00A79141 /* Info.plist */, - D66B16861CE46E8900E5638A /* LaunchScreen.storyboard */, - 520BC0381C869159008CFBC3 /* GoogleService-Info.plist */, - 5292271D1C85FB5500C89379 /* src */, - 529226D41C85F68000C89379 /* Frameworks */, - 529226D31C85F68000C89379 /* Products */, - ); - sourceTree = ""; - }; - 529226D31C85F68000C89379 /* Products */ = { - isa = PBXGroup; - children = ( - 529226D21C85F68000C89379 /* integration_test.app */, - ); - name = Products; - sourceTree = ""; - }; - 529226D41C85F68000C89379 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 529226D51C85F68000C89379 /* Foundation.framework */, - 529226D71C85F68000C89379 /* CoreGraphics.framework */, - 529226D91C85F68000C89379 /* UIKit.framework */, - 529226EE1C85F68000C89379 /* XCTest.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 5292271D1C85FB5500C89379 /* src */ = { - isa = PBXGroup; - children = ( - D603B7252819C8CA008A979F /* empty.swift */, - D62CCBC122F367320099BE9F /* gmock.h */, - D62CCBBF22F367140099BE9F /* gmock-all.cc */, - D67D355622BABD2100292C1D /* gtest-all.cc */, - D67D355722BABD2100292C1D /* gtest.h */, - D6C179EF22CB32A000C2651A /* app_framework.cc */, - D6C179ED22CB323300C2651A /* app_framework.h */, - D6C179EC22CB323300C2651A /* firebase_test_framework.cc */, - D6C179EB22CB323300C2651A /* firebase_test_framework.h */, - D61C5F9222BABAD100A79141 /* integration_test.cc */, - 5292271E1C85FB5B00C89379 /* ios */, - ); - name = src; - sourceTree = ""; - }; - 5292271E1C85FB5B00C89379 /* ios */ = { - isa = PBXGroup; - children = ( - D6C179E722CB322900C2651A /* ios_app_framework.mm */, - D6C179E822CB322900C2651A /* ios_firebase_test_framework.mm */, - ); - name = ios; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 529226D11C85F68000C89379 /* integration_test */ = { - isa = PBXNativeTarget; - buildConfigurationList = 529226F91C85F68000C89379 /* Build configuration list for PBXNativeTarget "integration_test" */; - buildPhases = ( - 529226CE1C85F68000C89379 /* Sources */, - 529226CF1C85F68000C89379 /* Frameworks */, - 529226D01C85F68000C89379 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = integration_test; - productName = testapp; - productReference = 529226D21C85F68000C89379 /* integration_test.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 529226CA1C85F68000C89379 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0640; - ORGANIZATIONNAME = Google; - TargetAttributes = { - 529226D11C85F68000C89379 = { - CreatedOnToolsVersion = 6.4; - DevelopmentTeam = EQHXZ8M8AV; - LastSwiftMigration = 1320; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = 529226CD1C85F68000C89379 /* Build configuration list for PBXProject "integration_test" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - English, - en, - ); - mainGroup = 529226C91C85F68000C89379; - productRefGroup = 529226D31C85F68000C89379 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 529226D11C85F68000C89379 /* integration_test */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 529226D01C85F68000C89379 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - D61C5F8E22BABA9C00A79141 /* Images.xcassets in Resources */, - D66B16871CE46E8900E5638A /* LaunchScreen.storyboard in Resources */, - 520BC0391C869159008CFBC3 /* GoogleService-Info.plist in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 529226CE1C85F68000C89379 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - D67D355822BABD2200292C1D /* gtest-all.cc in Sources */, - D62CCBC022F367140099BE9F /* gmock-all.cc in Sources */, - D6C179EA22CB322900C2651A /* ios_firebase_test_framework.mm in Sources */, - D61C5F9622BABAD200A79141 /* integration_test.cc in Sources */, - D6C179E922CB322900C2651A /* ios_app_framework.mm in Sources */, - D603B7262819C8CA008A979F /* empty.swift in Sources */, - D6C179F022CB32A000C2651A /* app_framework.cc in Sources */, - D6C179EE22CB323300C2651A /* firebase_test_framework.cc in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 529226F71C85F68000C89379 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 529226F81C85F68000C89379 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 529226FA1C85F68000C89379 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)", - ); - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "\"$(SRCROOT)/src\"", - "\"$(SRCROOT)/external/googletest/src/googletest/include\"", - "\"$(SRCROOT)/external/googletest/src/googlemock/include\"", - "\"$(SRCROOT)/external/googletest/src/googletest\"", - "\"$(SRCROOT)/external/googletest/src/googlemock\"", - ); - INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.3; - WRAPPER_EXTENSION = app; - }; - name = Debug; - }; - 529226FB1C85F68000C89379 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)", - ); - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "\"$(SRCROOT)/src\"", - "\"$(SRCROOT)/external/googletest/src/googletest/include\"", - "\"$(SRCROOT)/external/googletest/src/googlemock/include\"", - "\"$(SRCROOT)/external/googletest/src/googletest\"", - "\"$(SRCROOT)/external/googletest/src/googlemock\"", - ); - INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.3; - WRAPPER_EXTENSION = app; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 529226CD1C85F68000C89379 /* Build configuration list for PBXProject "integration_test" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 529226F71C85F68000C89379 /* Debug */, - 529226F81C85F68000C89379 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 529226F91C85F68000C89379 /* Build configuration list for PBXNativeTarget "integration_test" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 529226FA1C85F68000C89379 /* Debug */, - 529226FB1C85F68000C89379 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 529226CA1C85F68000C89379 /* Project object */; -} diff --git a/dynamic_links/integration_test/proguard.pro b/dynamic_links/integration_test/proguard.pro deleted file mode 100644 index 2d04b8a9a5..0000000000 --- a/dynamic_links/integration_test/proguard.pro +++ /dev/null @@ -1,2 +0,0 @@ --ignorewarnings --keep,includedescriptorclasses public class com.google.firebase.example.LoggingUtils { * ; } diff --git a/dynamic_links/integration_test/res/layout/main.xml b/dynamic_links/integration_test/res/layout/main.xml deleted file mode 100644 index cbe90c3ebe..0000000000 --- a/dynamic_links/integration_test/res/layout/main.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - diff --git a/dynamic_links/integration_test/res/values/strings.xml b/dynamic_links/integration_test/res/values/strings.xml deleted file mode 100644 index 0c05e26ec7..0000000000 --- a/dynamic_links/integration_test/res/values/strings.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - Firebase Dynamic Links Integration Test - diff --git a/dynamic_links/integration_test/settings.gradle b/dynamic_links/integration_test/settings.gradle deleted file mode 100644 index 8b600af5be..0000000000 --- a/dynamic_links/integration_test/settings.gradle +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -def firebase_cpp_sdk_dir = System.getProperty('firebase_cpp_sdk.dir') -if (firebase_cpp_sdk_dir == null || firebase_cpp_sdk_dir.isEmpty()) { - firebase_cpp_sdk_dir = System.getenv('FIREBASE_CPP_SDK_DIR') - if (firebase_cpp_sdk_dir == null || firebase_cpp_sdk_dir.isEmpty()) { - if ((file('../../cpp_sdk_version.json')).exists()) { - firebase_cpp_sdk_dir = file('../..').absolutePath - } - else if ((file('firebase_cpp_sdk')).exists()) { - firebase_cpp_sdk_dir = 'firebase_cpp_sdk' - } else { - throw new StopActionException( - 'firebase_cpp_sdk.dir property or the FIREBASE_CPP_SDK_DIR ' + - 'environment variable must be set to reference the Firebase C++ ' + - 'SDK install directory. This is used to configure static library ' + - 'and C/C++ include paths for the SDK.') - } - } -} -if (!(new File(firebase_cpp_sdk_dir)).exists()) { - throw new StopActionException( - sprintf('Firebase C++ SDK directory %s does not exist', - firebase_cpp_sdk_dir)) -} -gradle.ext.firebase_cpp_sdk_dir = "$firebase_cpp_sdk_dir" -includeBuild("$firebase_cpp_sdk_dir") { - name = "firebase_cpp_sdk" -} diff --git a/dynamic_links/integration_test/src/integration_test.cc b/dynamic_links/integration_test/src/integration_test.cc deleted file mode 100644 index df73206cb3..0000000000 --- a/dynamic_links/integration_test/src/integration_test.cc +++ /dev/null @@ -1,711 +0,0 @@ -// Copyright 2019 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include -#include -#include -#include -#include - -#include "app_framework.h" // NOLINT -#include "firebase/app.h" -#include "firebase/dynamic_links.h" -#include "firebase/dynamic_links/components.h" -#include "firebase/internal/platform.h" -#include "firebase/log.h" -#include "firebase/util.h" -#include "firebase_test_framework.h" // NOLINT - -// The TO_STRING macro is useful for command line defined strings as the quotes -// get stripped. -#define TO_STRING_EXPAND(X) #X -#define TO_STRING(X) TO_STRING_EXPAND(X) - -// Path to the Firebase config file to load. -#ifdef FIREBASE_CONFIG -#define FIREBASE_CONFIG_STRING TO_STRING(FIREBASE_CONFIG) -#else -#define FIREBASE_CONFIG_STRING "" -#endif // FIREBASE_CONFIG - -namespace firebase_testapp_automated { - -using app_framework::LogDebug; -using app_framework::LogInfo; - -using app_framework::ProcessEvents; -using firebase_test_framework::FirebaseTest; - -// Bundle IDs needed for opening Dynamic Links. -static const char kIOSBundleID[] = - "com.google.FirebaseCppDynamicLinksTestApp.dev"; -static const char kAndroidBundleID[] = - "com.google.android.dynamiclinks.testapp"; -static const char kIOSAppStoreID[] = "2233445566"; // Placeholder ID. - -static const char kDomainUriPrefixInvalidError[] = - "kDomainUriPrefix is not valid, link shortening will fail.\n" - "To resolve this:\n" - "* Goto the Firebase console https://firebase.google.com/console/\n" - "* Click on the Dynamic Links tab\n" - "* Copy the URI prefix e.g https://a12cd.app.goo.gl or " - " https://your-project.page.link\n" - "* Replace the value of kDomainUriPrefix with the copied URI prefix.\n"; - -// IMPORTANT: You need to set this to a valid URI prefix from the Firebase -// console (see kDomainUriPrefixInvalidError for the details). -static const char* kDomainUriPrefix = "https://REPLACE_WITH_YOUR_URI_PREFIX"; - -#define TARGET_URL_PREFIX "https://mysite.example.com" - -// When one of the tests tries to open a URL, it suppresses the other tests -// that are attempting to do the same, since only one URL can be opened at a -// time. It does so by setting the "current test" flag to its own test name. -static const char kCurrentTestKey[] = "openurl_current_test"; - -class TestListener; - -class FirebaseDynamicLinksTest : public FirebaseTest { - public: - static void SetUpTestSuite(); - static void TearDownTestSuite(); - - protected: - // Try to claim the "current test" flag, returning true if successful and - // false if not. Because tests run in sequence, this does not actually - // require any mutexes. This returns true if it was already claimed by this - // test, or if no test was claiming it before (in which case, now this test - // is). - bool ClaimCurrentTest(const char* test_name); - // Release the "current test" flag, allowing the next test to run. - void ReleaseCurrentTest(); - - static firebase::App* shared_app_; - static TestListener* shared_listener_; - static bool is_desktop_stub_; - // A list of persistent keys we've saved on the device, to be erased on - // shutdown after all tests are finished. - static std::vector cleanup_persistent_keys_; -}; - -firebase::App* FirebaseDynamicLinksTest::shared_app_ = nullptr; -TestListener* FirebaseDynamicLinksTest::shared_listener_ = nullptr; -bool FirebaseDynamicLinksTest::is_desktop_stub_ = false; -// NOLINTNEXTLINE -std::vector FirebaseDynamicLinksTest::cleanup_persistent_keys_; - -// Handles a received dynamic link. -class TestListener : public firebase::dynamic_links::Listener { - public: - TestListener() : received_link_(false) {} - void OnDynamicLinkReceived( - const firebase::dynamic_links::DynamicLink* dynamic_link) override { - LogInfo("Received dynamic link: %s", dynamic_link->url.c_str()); - link_ = *dynamic_link; - received_link_ = true; - } - - bool WaitForDynamicLink(firebase::dynamic_links::DynamicLink* link_output) { - const int kWaitSeconds = 10; - for (int i = 0; i < kWaitSeconds; i++) { - ProcessEvents(1000); - if (received_link_) { - *link_output = link_; - return true; - } - } - return false; - } - bool received_link_; - firebase::dynamic_links::DynamicLink link_; -}; - -void FirebaseDynamicLinksTest::SetUpTestSuite() { - FindFirebaseConfig(FIREBASE_CONFIG_STRING); - - firebase::SetLogLevel(firebase::kLogLevelDebug); - LogDebug("Initialize Firebase App."); - -#if defined(__ANDROID__) - shared_app_ = ::firebase::App::Create(app_framework::GetJniEnv(), - app_framework::GetActivity()); -#else - shared_app_ = ::firebase::App::Create(); -#endif // defined(__ANDROID__) - - LogDebug("Initializing Firebase Dynamic Links."); - - shared_listener_ = new TestListener(); - - ::firebase::ModuleInitializer initializer; - initializer.Initialize( - shared_app_, shared_listener_, - [](::firebase::App* app, void* listener_void) { - LogDebug("Try to initialize Firebase Dynamic Links"); - firebase::InitResult result; - result = firebase::dynamic_links::Initialize( - *app, reinterpret_cast( - listener_void)); - return result; - }); - - FirebaseTest::WaitForCompletion(initializer.InitializeLastResult(), - "Initialize"); - - ASSERT_EQ(initializer.InitializeLastResult().error(), 0) - << initializer.InitializeLastResult().error_message(); - - is_desktop_stub_ = false; -#if !defined(__ANDROID__) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) - is_desktop_stub_ = true; -#endif // !defined(__ANDROID__) && !(defined(TARGET_OS_IPHONE) && - // TARGET_OS_IPHONE) - - LogDebug("Successfully initialized Firebase Dynamic Links."); -} - -void FirebaseDynamicLinksTest::TearDownTestSuite() { - // On teardown, delete all the persistent keys we should clean up, as long as - // there is no longer a current test running. - std::string value; - if (GetPersistentString(kCurrentTestKey, &value) && !value.empty()) { - // Don't clean up the persistent keys yet, not until all the tests are done. - return; - } - LogDebug("Tests finished, cleaning up all persistent keys."); - for (int i = 0; i < cleanup_persistent_keys_.size(); ++i) { - SetPersistentString(cleanup_persistent_keys_[i].c_str(), nullptr); - } - cleanup_persistent_keys_.clear(); - - LogDebug("Shutdown Firebase Dynamic Links."); - firebase::dynamic_links::Terminate(); - - delete shared_listener_; - shared_listener_ = nullptr; - - LogDebug("Shutdown Firebase App."); - delete shared_app_; - shared_app_ = nullptr; - - ProcessEvents(100); -} - -// Test cases below. - -TEST_F(FirebaseDynamicLinksTest, TestInitializeAndTerminate) { - // Already tested via SetUp() and TearDown(). -} - -TEST_F(FirebaseDynamicLinksTest, CheckForDomainUriPrefix) { - ASSERT_EQ(strstr(kDomainUriPrefix, "REPLACE_WITH"), nullptr) - << kDomainUriPrefixInvalidError; -} - -TEST_F(FirebaseDynamicLinksTest, TestCreateLongLink) { - firebase::dynamic_links::GoogleAnalyticsParameters analytics_parameters; - analytics_parameters.source = "mysource"; - analytics_parameters.medium = "mymedium"; - analytics_parameters.campaign = "mycampaign"; - analytics_parameters.term = "myterm"; - analytics_parameters.content = "mycontent"; - - firebase::dynamic_links::IOSParameters ios_parameters("com.myapp.bundleid"); - ios_parameters.fallback_url = TARGET_URL_PREFIX "/fallback"; - ios_parameters.custom_scheme = "mycustomscheme"; - ios_parameters.minimum_version = "1.2.3"; - ios_parameters.ipad_bundle_id = "com.myapp.bundleid.ipad"; - ios_parameters.ipad_fallback_url = TARGET_URL_PREFIX "/fallbackipad"; - - firebase::dynamic_links::ITunesConnectAnalyticsParameters - app_store_parameters; - app_store_parameters.affiliate_token = "abcdefg"; - app_store_parameters.campaign_token = "hijklmno"; - app_store_parameters.provider_token = "pq-rstuv"; - - firebase::dynamic_links::AndroidParameters android_parameters( - "com.myapp.packageid"); - android_parameters.fallback_url = TARGET_URL_PREFIX "/fallback"; - android_parameters.minimum_version = 12; - - firebase::dynamic_links::SocialMetaTagParameters social_parameters; - social_parameters.title = "My App!"; - social_parameters.description = "My app is awesome!"; - social_parameters.image_url = TARGET_URL_PREFIX "/someimage.jpg"; - - firebase::dynamic_links::DynamicLinkComponents components( - "https://google.com/abc", kDomainUriPrefix); - components.google_analytics_parameters = &analytics_parameters; - components.ios_parameters = &ios_parameters; - components.itunes_connect_analytics_parameters = &app_store_parameters; - components.android_parameters = &android_parameters; - components.social_meta_tag_parameters = &social_parameters; - - firebase::dynamic_links::GeneratedDynamicLink generated_link = - firebase::dynamic_links::GetLongLink(components); - - if (is_desktop_stub_) { - // On desktop, it's enough that we just don't crash. - SUCCEED(); - return; - } - - EXPECT_TRUE(generated_link.error.empty()); - EXPECT_NE(generated_link.url, ""); - EXPECT_EQ(generated_link.url.find(kDomainUriPrefix), 0) - << "Dynamic Link URL (" << generated_link.url - << ") does not begin with Domain URI Prefix (" << kDomainUriPrefix << ")"; - if (!generated_link.warnings.empty()) { - LogDebug("GetLongLink warnings:"); - for (auto it = generated_link.warnings.begin(); - it != generated_link.warnings.end(); ++it) { - LogDebug(" %s", it->c_str()); - } - } -} - -TEST_F(FirebaseDynamicLinksTest, TestGetShortLinkFromComponents) { - firebase::dynamic_links::GoogleAnalyticsParameters analytics_parameters; - analytics_parameters.source = "mysource"; - analytics_parameters.medium = "mymedium"; - analytics_parameters.campaign = "mycampaign"; - analytics_parameters.term = "myterm"; - analytics_parameters.content = "mycontent"; - - firebase::dynamic_links::IOSParameters ios_parameters("com.myapp.bundleid"); - ios_parameters.fallback_url = TARGET_URL_PREFIX "/fallback"; - ios_parameters.custom_scheme = "mycustomscheme"; - ios_parameters.minimum_version = "1.2.3"; - ios_parameters.ipad_bundle_id = "com.myapp.bundleid.ipad"; - ios_parameters.ipad_fallback_url = TARGET_URL_PREFIX "/fallbackipad"; - - firebase::dynamic_links::ITunesConnectAnalyticsParameters - app_store_parameters; - app_store_parameters.affiliate_token = "abcdefg"; - app_store_parameters.campaign_token = "hijklmno"; - app_store_parameters.provider_token = "pq-rstuv"; - - firebase::dynamic_links::AndroidParameters android_parameters( - "com.myapp.packageid"); - android_parameters.fallback_url = TARGET_URL_PREFIX "/fallback"; - android_parameters.minimum_version = 12; - - firebase::dynamic_links::SocialMetaTagParameters social_parameters; - social_parameters.title = "My App!"; - social_parameters.description = "My app is awesome!"; - social_parameters.image_url = TARGET_URL_PREFIX "/someimage.jpg"; - - firebase::dynamic_links::DynamicLinkComponents components( - "https://google.com/def", kDomainUriPrefix); - components.google_analytics_parameters = &analytics_parameters; - components.ios_parameters = &ios_parameters; - components.itunes_connect_analytics_parameters = &app_store_parameters; - components.android_parameters = &android_parameters; - components.social_meta_tag_parameters = &social_parameters; - - firebase::Future future; - - FLAKY_TEST_SECTION_BEGIN(); // Occasionally there can be a connection error. - future = firebase::dynamic_links::GetShortLink(components); - WaitForCompletion(future, "GetShortLinkFromComponents"); - FLAKY_TEST_SECTION_END(); - - if (is_desktop_stub_) { - // On desktop, it's enough that we just don't crash. - SUCCEED(); - return; - } - - const firebase::dynamic_links::GeneratedDynamicLink& generated_link = - *future.result(); - - EXPECT_TRUE(generated_link.error.empty()); - EXPECT_NE(generated_link.url, ""); - EXPECT_EQ(generated_link.url.find(kDomainUriPrefix), 0) - << "Dynamic Link URL (" << generated_link.url - << ") does not begin with Domain URI Prefix (" << kDomainUriPrefix << ")"; - if (!generated_link.warnings.empty()) { - LogDebug("GetShortLinkFromComponents warnings:"); - for (auto it = generated_link.warnings.begin(); - it != generated_link.warnings.end(); ++it) { - LogDebug(" %s", it->c_str()); - } - } -} - -TEST_F(FirebaseDynamicLinksTest, TestGetShortLinkFromLongLink) { - firebase::dynamic_links::GoogleAnalyticsParameters analytics_parameters; - analytics_parameters.source = "mysource"; - analytics_parameters.medium = "mymedium"; - analytics_parameters.campaign = "mycampaign"; - analytics_parameters.term = "myterm"; - analytics_parameters.content = "mycontent"; - - firebase::dynamic_links::IOSParameters ios_parameters("com.myapp.bundleid"); - ios_parameters.fallback_url = TARGET_URL_PREFIX "/fallback"; - ios_parameters.custom_scheme = "mycustomscheme"; - ios_parameters.minimum_version = "1.2.3"; - ios_parameters.ipad_bundle_id = "com.myapp.bundleid.ipad"; - ios_parameters.ipad_fallback_url = TARGET_URL_PREFIX "/fallbackipad"; - - firebase::dynamic_links::ITunesConnectAnalyticsParameters - app_store_parameters; - app_store_parameters.affiliate_token = "abcdefg"; - app_store_parameters.campaign_token = "hijklmno"; - app_store_parameters.provider_token = "pq-rstuv"; - - firebase::dynamic_links::AndroidParameters android_parameters( - "com.myapp.packageid"); - android_parameters.fallback_url = TARGET_URL_PREFIX "/fallback"; - android_parameters.minimum_version = 12; - - firebase::dynamic_links::SocialMetaTagParameters social_parameters; - social_parameters.title = "My App!"; - social_parameters.description = "My app is awesome!"; - social_parameters.image_url = TARGET_URL_PREFIX "/someimage.jpg"; - - firebase::dynamic_links::DynamicLinkComponents components( - "https://google.com/ghi", kDomainUriPrefix); - components.google_analytics_parameters = &analytics_parameters; - components.ios_parameters = &ios_parameters; - components.itunes_connect_analytics_parameters = &app_store_parameters; - components.android_parameters = &android_parameters; - components.social_meta_tag_parameters = &social_parameters; - - firebase::dynamic_links::GeneratedDynamicLink long_link = - firebase::dynamic_links::GetLongLink(components); - - if (is_desktop_stub_) { - // On desktop, it's enough that we just don't crash. - SUCCEED(); - return; - } - - EXPECT_NE(long_link.url, ""); - - firebase::dynamic_links::DynamicLinkOptions options; - options.path_length = firebase::dynamic_links::kPathLengthShort; - firebase::Future future; - - FLAKY_TEST_SECTION_BEGIN(); // Occasional connection errors. - future = - firebase::dynamic_links::GetShortLink(long_link.url.c_str(), options); - WaitForCompletion(future, "GetShortLinkFromLongLink"); - FLAKY_TEST_SECTION_END(); - - const firebase::dynamic_links::GeneratedDynamicLink& generated_link = - *future.result(); - - EXPECT_TRUE(generated_link.error.empty()); - EXPECT_NE(generated_link.url, ""); - EXPECT_EQ(generated_link.url.find(kDomainUriPrefix), 0) - << "Dynamic Link URL (" << generated_link.url - << ") does not begin with Domain URI Prefix (" << kDomainUriPrefix << ")"; - if (!generated_link.warnings.empty()) { - LogDebug("GetShortLinkFromLongLink warnings:"); - for (auto it = generated_link.warnings.begin(); - it != generated_link.warnings.end(); ++it) { - LogDebug(" %s", it->c_str()); - } - } -} - -bool FirebaseDynamicLinksTest::ClaimCurrentTest(const char* test_name) { - // Tests using OpenUrlInBrowser must be run one at a time per run of the app. - // The workflow for these tests is: - // - // Run #1: Test A opens its link in browser, tests B & C do nothing. - // Run #2: Test A verifies that its link loaded, test B opens its link in - // browser, test C does nothing. - // Run #3: Test A remembers whether its link had loaded, test B verifies that - // its link loaded, test C opens its link in browser. - // Run #4: Tests A & B remember whether their links had loaded, test C - // verifies that its link loaded. - // - // This is accomplished by setting the value of kCurrentTestKey, which tells - // us which of the tests is currently doing its thing. Each test can also set - // a state variable saying whether they are opening the link in browser (the - // starting state), verifying that the link opened, or previously opened (or - // failed to open) the link. Tests that previously failed to open the link - // will continue to register a FAIL until all the tests are finished. - std::string value; - if (!GetPersistentString(kCurrentTestKey, &value) || value == test_name) { - // If not already set to it, take ownership of the current test. - if (value != test_name) { - SetPersistentString(kCurrentTestKey, test_name); - } - return true; - } - return false; -} - -void FirebaseDynamicLinksTest::ReleaseCurrentTest() { - SetPersistentString(kCurrentTestKey, nullptr); -} - -static firebase::dynamic_links::DynamicLinkComponents GenerateComponentsForTest( - const char* url) { - static firebase::dynamic_links::AndroidParameters android_parameters( - kAndroidBundleID); - static firebase::dynamic_links::IOSParameters ios_parameters(kIOSBundleID); - ios_parameters.app_store_id = kIOSAppStoreID; - static firebase::dynamic_links::SocialMetaTagParameters social_parameters; - static firebase::dynamic_links::ITunesConnectAnalyticsParameters - app_store_parameters; - static firebase::dynamic_links::GoogleAnalyticsParameters - analytics_parameters; - firebase::dynamic_links::DynamicLinkComponents components(url, - kDomainUriPrefix); - components.google_analytics_parameters = &analytics_parameters; - components.ios_parameters = &ios_parameters; - components.itunes_connect_analytics_parameters = &app_store_parameters; - components.android_parameters = &android_parameters; - components.social_meta_tag_parameters = &social_parameters; - return components; -} -static const char kStateSentLink[] = "sentLink"; -static const char kStateReceivedLink[] = "receivedLink"; -static const char kStateReceivedLinkFail[] = "receivedLinkFail"; - -TEST_F(FirebaseDynamicLinksTest, TestOpeningLongLinkInRunningApp) { - // On iOS, the dynamic link landing page requires a click. - // On Android, the first time a dynamic link is clicked on the device, Google - // Play services shows a TOS popup. Either way, this test requires user - // interaction. -#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || defined(__ANDROID__) - TEST_REQUIRES_USER_INTERACTION; -#endif // (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || - // defined(__ANDROID__) - - // This test uses a persistent key to keep track of how it's running. - const char kUrlToOpen[] = "https://google.com/test_opening_long_link"; - std::string persistent_key_str = test_info_->name(); - const char* persistent_key = persistent_key_str.c_str(); - - bool owns_current_test = ClaimCurrentTest(persistent_key); - - cleanup_persistent_keys_.push_back(persistent_key); - std::string value; - if (owns_current_test && !GetPersistentString(persistent_key, &value)) { - // The first time, create a dynamic link and open it in the browser. - LogDebug("First run, creating and opening long dynamic link..."); - - firebase::dynamic_links::DynamicLinkComponents components = - GenerateComponentsForTest(kUrlToOpen); - firebase::dynamic_links::GeneratedDynamicLink link = - firebase::dynamic_links::GetLongLink(components); - - if (is_desktop_stub_) { - // On desktop, it's enough that we just don't crash. - LogDebug("Succeeded as stub."); - SUCCEED(); - return; - } - EXPECT_TRUE(link.error.empty()); - SetPersistentString(persistent_key, kStateSentLink); - // This will trigger the test to start over. - OpenUrlInBrowser(link.url.c_str()); - exit(0); // Kill the app after opening the URL so it can be restarted - // properly. - } else if (owns_current_test && GetPersistentString(persistent_key, &value) && - value == kStateSentLink) { - // The second time, check that we received the dynamic link. - LogDebug("Second run, checking for dynamic link..."); - firebase::dynamic_links::DynamicLink got_link; - EXPECT_TRUE(shared_listener_->WaitForDynamicLink(&got_link)); - EXPECT_EQ(got_link.url, kUrlToOpen); - if (got_link.url == kUrlToOpen) { - SetPersistentString(persistent_key, kStateReceivedLink); - } else { - SetPersistentString(persistent_key, kStateReceivedLinkFail); - } - ReleaseCurrentTest(); - } else if (GetPersistentString(persistent_key, &value) && - value == kStateReceivedLink) { - // Already verified the link was correct. - LogDebug("Previously verified that dynamic link was received."); - SUCCEED(); - } else if (GetPersistentString(persistent_key, &value) && - value == kStateReceivedLinkFail) { - // Already verified the link failed. - FAIL() << "Previous attempt to get link failed."; - } else { - LogDebug("Skipping this test because another test has taken ownership."); - SUCCEED(); - } -} - -TEST_F(FirebaseDynamicLinksTest, TestOpeningShortLinkFromLongLinkInRunningApp) { - // On iOS, the dynamic link landing page requires a click. - // On Android, the first time a dynamic link is clicked on the device, Google - // Play services shows a TOS popup. Either way, this test requires user - // interaction. -#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || defined(__ANDROID__) - TEST_REQUIRES_USER_INTERACTION; -#endif // (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || - // defined(__ANDROID__) - - // This test uses a persistent key to keep track of how it's running. - const char kUrlToOpen[] = - "https://google.com/test_opening_short_link_from_long_link"; - std::string persistent_key_str = test_info_->name(); - const char* persistent_key = persistent_key_str.c_str(); - - bool owns_current_test = ClaimCurrentTest(persistent_key); - - cleanup_persistent_keys_.push_back(persistent_key); - std::string value; - if (owns_current_test && !GetPersistentString(persistent_key, &value)) { - // The first time, create a dynamic link and open it in the browser. - LogDebug( - "First run, creating and opening short dynamic link from long link..."); - firebase::dynamic_links::DynamicLinkComponents components = - GenerateComponentsForTest(kUrlToOpen); - firebase::dynamic_links::GeneratedDynamicLink long_link = - firebase::dynamic_links::GetLongLink(components); - // Shorten link. - firebase::dynamic_links::DynamicLinkOptions options; - options.path_length = firebase::dynamic_links::kPathLengthShort; - firebase::Future future; - - FLAKY_TEST_SECTION_BEGIN(); // Occasional connection errors. - future = - firebase::dynamic_links::GetShortLink(long_link.url.c_str(), options); - WaitForCompletion(future, "GetShortLinkFromLongLink"); - FLAKY_TEST_SECTION_END(); - - if (is_desktop_stub_) { - // On desktop, it's enough that we just don't crash. - LogDebug("Succeeded as stub."); - SUCCEED(); - return; - } - const firebase::dynamic_links::GeneratedDynamicLink& link = - *future.result(); - - EXPECT_TRUE(link.error.empty()); - SetPersistentString(persistent_key, kStateSentLink); - // This will trigger the test to start over. - OpenUrlInBrowser(link.url.c_str()); - exit(0); // Kill the app after opening the URL so it can be restarted - // properly; - } else if (owns_current_test && GetPersistentString(persistent_key, &value) && - value == kStateSentLink) { - // The second time, check that we received the dynamic link. - LogDebug("Second run, checking for dynamic link..."); - firebase::dynamic_links::DynamicLink got_link; - EXPECT_TRUE(shared_listener_->WaitForDynamicLink(&got_link)); - EXPECT_EQ(got_link.url, kUrlToOpen); - if (got_link.url == kUrlToOpen) { - SetPersistentString(persistent_key, kStateReceivedLink); - } else { - SetPersistentString(persistent_key, kStateReceivedLinkFail); - } - ReleaseCurrentTest(); - } else if (GetPersistentString(persistent_key, &value) && - value == kStateReceivedLink) { - // Already verified the link was correct. - LogDebug("Previously verified that dynamic link was received."); - SUCCEED(); - } else if (GetPersistentString(persistent_key, &value) && - value == kStateReceivedLinkFail) { - // Already verified the link failed. - FAIL() << "Previous attempt to get link failed."; - } else { - LogDebug("Skipping this test because another test has taken ownership."); - SUCCEED(); - } -} - -TEST_F(FirebaseDynamicLinksTest, - TestOpeningShortLinkFromComponentsInRunningApp) { - // On iOS, the dynamic link landing page requires a click. - // On Android, the first time a dynamic link is clicked on the device, Google - // Play services shows a TOS popup. Either way, this test requires user - // interaction. -#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || defined(__ANDROID__) - TEST_REQUIRES_USER_INTERACTION; -#endif // (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || - // defined(__ANDROID__) - - // This test uses a persistent key to keep track of how it's running. - const char kUrlToOpen[] = - "https://google.com/test_opening_short_link_from_components"; - std::string persistent_key_str = test_info_->name(); - const char* persistent_key = persistent_key_str.c_str(); - - bool owns_current_test = ClaimCurrentTest(persistent_key); - - cleanup_persistent_keys_.push_back(persistent_key); - std::string value; - if (owns_current_test && !GetPersistentString(persistent_key, &value)) { - // The first time, create a dynamic link and open it in the browser. - LogDebug( - "First run, creating and opening short dynamic link from " - "components..."); - firebase::dynamic_links::DynamicLinkComponents components = - GenerateComponentsForTest(kUrlToOpen); - - firebase::Future future; - FLAKY_TEST_SECTION_BEGIN(); // Occasional connection errors. - future = firebase::dynamic_links::GetShortLink(components); - WaitForCompletion(future, "GetShortLinkFromLongLink"); - FLAKY_TEST_SECTION_END(); // Occasional connection errors. - - if (is_desktop_stub_) { - // On desktop, it's enough that we just don't crash. - LogDebug("Succeeded as stub."); - SUCCEED(); - return; - } - - const firebase::dynamic_links::GeneratedDynamicLink& link = - *future.result(); - - EXPECT_TRUE(link.error.empty()); - SetPersistentString(persistent_key, kStateSentLink); - // This will trigger the test to start over. - OpenUrlInBrowser(link.url.c_str()); - exit(0); // Kill the app after opening the URL so it can be restarted - // properly. - } else if (owns_current_test && GetPersistentString(persistent_key, &value) && - value == kStateSentLink) { - // The second time, check that we received the dynamic link. - LogDebug("Second run, checking for dynamic link..."); - firebase::dynamic_links::DynamicLink got_link; - EXPECT_TRUE(shared_listener_->WaitForDynamicLink(&got_link)); - EXPECT_EQ(got_link.url, kUrlToOpen); - if (got_link.url == kUrlToOpen) { - SetPersistentString(persistent_key, kStateReceivedLink); - } else { - SetPersistentString(persistent_key, kStateReceivedLinkFail); - } - ReleaseCurrentTest(); - } else if (GetPersistentString(persistent_key, &value) && - value == kStateReceivedLink) { - // Already verified the link was correct. - LogDebug("Previously verified that dynamic link was received."); - SUCCEED(); - } else if (GetPersistentString(persistent_key, &value) && - value == kStateReceivedLinkFail) { - // Already verified the link failed. - FAIL() << "Previous attempt to get link failed."; - } else { - LogDebug("Skipping this test because another test has taken ownership."); - SUCCEED(); - } -} -} // namespace firebase_testapp_automated diff --git a/dynamic_links/samples/src/doc_samples.cc b/dynamic_links/samples/src/doc_samples.cc deleted file mode 100644 index 89312b55ca..0000000000 --- a/dynamic_links/samples/src/doc_samples.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// WARNING: Code from this file is included verbatim in the Auth C++ -// documentation. Only change existing code if it is safe to release -// to the public. Otherwise, a tech writer may make an unrelated -// modification, regenerate the docs, and unwittingly release an -// unannounced modification to the public. - -// [START dynamic_link_includes] -#include "firebase/app.h" -#include "firebase/dynamic_links.h" - -// Needed for creating links only. -#include "firebase/dynamic_links/components.h" -// [END dynamic_link_includes] - -#if defined(__ANDROID__) -JNIEnv* my_jni_env = nullptr; -jobject my_activity = nullptr; -#endif // defined(__ANDROID__) - -void CreateLinks() { - { - // [START dlink_create_longlink_minimal] - firebase::dynamic_links::IOSParameters ios_parameters("com.example.ios"); - - firebase::dynamic_links::AndroidParameters android_parameters( - "com.example.android.package_name"); - - firebase::dynamic_links::DynamicLinkComponents components( - "https://www.example.com/", "example.page.link"); - components.android_parameters = &android_parameters; - components.ios_parameters = &ios_parameters; - - firebase::dynamic_links::GeneratedDynamicLink long_link = - firebase::dynamic_links::GetLongLink(components); - // [END dlink_create_longlink_minimal] - - // [START dlink_create_shortlink_minimal] - firebase::dynamic_links::DynamicLinkOptions short_link_options; - short_link_options.path_length = firebase::dynamic_links::kPathLengthShort; - - firebase::Future result = - firebase::dynamic_links::GetShortLink(components, short_link_options); - // [END dlink_create_shortlink_minimal] - - // [START poll_dlink_future] - if (result.status() == firebase::kFutureStatusComplete) { - if (result.error() == firebase::dynamic_links::kErrorCodeSuccess) { - firebase::dynamic_links::GeneratedDynamicLink link = *result.result(); - printf("Create short link succeeded: %s\n", link.url.c_str()); - } else { - printf("Created short link failed with error '%s'\n", - result.error_message()); - } - } - // [END poll_dlink_future] - } -} - -// [START dlink_listener] -class Listener : public firebase::dynamic_links::Listener { - public: - // Called on the client when a dynamic link arrives. - void OnDynamicLinkReceived( - const firebase::dynamic_links::DynamicLink* dynamic_link) override { - printf("Received link: %s", dynamic_link->url.c_str()); - } -}; -// [END dlink_listener] diff --git a/dynamic_links/src/common.cc b/dynamic_links/src/common.cc deleted file mode 100644 index 0031246b29..0000000000 --- a/dynamic_links/src/common.cc +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "dynamic_links/src/common.h" - -#include - -#include "app/src/cleanup_notifier.h" -#include "app/src/invites/cached_receiver.h" -#include "app/src/invites/invites_receiver_internal.h" -#include "app/src/util.h" -#include "dynamic_links/src/include/firebase/dynamic_links.h" - -// Register the module initializer. -FIREBASE_APP_REGISTER_CALLBACKS( - dynamic_links, - { - if (app == ::firebase::App::GetInstance()) { - return firebase::dynamic_links::Initialize(*app, nullptr); - } - return kInitResultSuccess; - }, - { - if (app == ::firebase::App::GetInstance()) { - firebase::dynamic_links::Terminate(); - } - }, - false); - -namespace firebase { -namespace dynamic_links { - -namespace internal { -const char kDynamicLinksModuleName[] = "dynamic_links"; -} // namespace internal - -// Notifies a listener of a cached invite. -class CachedListenerNotifier : public invites::internal::ReceiverInterface { - public: - CachedListenerNotifier() : listener_(nullptr) {} - virtual ~CachedListenerNotifier() { SetListener(nullptr); } - - // Set the listener which should be notified of any cached or receiver - // links. - Listener* SetListener(Listener* listener) { - MutexLock lock(lock_); - Listener* previous_listener = listener_; - listener_ = listener; - receiver_.SetReceiver(listener ? this : nullptr); - return previous_listener; - } - - private: - // Callback called when an invite is received. If an error occurred, - // result_code should be non-zero. Otherwise, either invitation_id should be - // set, or deep_link_url should be set, or both. - void ReceivedInviteCallback( - const std::string& invitation_id, const std::string& deep_link_url, - invites::internal::InternalLinkMatchStrength match_strength, - int result_code, const std::string& error_message) override { - MutexLock lock(lock_); - if (listener_) { - if (!deep_link_url.empty()) { - DynamicLink link; - link.url = deep_link_url; - link.match_strength = static_cast(match_strength); - listener_->OnDynamicLinkReceived(&link); - } - } else { - receiver_.ReceivedInviteCallback(invitation_id, deep_link_url, - match_strength, result_code, - error_message); - } - } - - private: - // Protects access to members of this class. - Mutex lock_; - // End user's listener which is notified of invites. - Listener* listener_; - // Caches received links. - invites::internal::CachedReceiver receiver_; -}; - -static invites::internal::InvitesReceiverInternal* g_receiver = nullptr; -static CachedListenerNotifier* g_cached_receiver = nullptr; - -FutureData* FutureData::s_future_data_ = nullptr; - -// Create FutureData singleton. -FutureData* FutureData::Create() { - s_future_data_ = new FutureData(); - return s_future_data_; -} - -// Destroy the FutureData singleton. -void FutureData::Destroy() { - delete s_future_data_; - s_future_data_ = nullptr; -} - -// Get the Future data singleton. -FutureData* FutureData::Get() { return s_future_data_; } - -bool CreateReceiver(const App& app) { - assert(!g_cached_receiver && !g_receiver); - g_cached_receiver = new CachedListenerNotifier(); - g_receiver = invites::internal::InvitesReceiverInternal::CreateInstance( - app, g_cached_receiver); - if (!g_receiver) { - delete g_cached_receiver; - g_cached_receiver = nullptr; - return false; - } - if (!AppCallback::GetEnabledByName(internal::kDynamicLinksModuleName)) { - CleanupNotifier* cleanup_notifier = - CleanupNotifier::FindByOwner(const_cast(g_receiver->app())); - assert(cleanup_notifier); - cleanup_notifier->RegisterObject( - const_cast(internal::kDynamicLinksModuleName), [](void*) { - LogError( - "dynamic_links::Terminate() should be called before the " - "default app is destroyed."); - if (g_receiver) firebase::dynamic_links::Terminate(); - }); - } - return true; -} - -void DestroyReceiver() { - assert(g_cached_receiver && g_receiver); - if (!AppCallback::GetEnabledByName(internal::kDynamicLinksModuleName)) { - CleanupNotifier* cleanup_notifier = - CleanupNotifier::FindByOwner(const_cast(g_receiver->app())); - assert(cleanup_notifier); - cleanup_notifier->UnregisterObject( - const_cast(internal::kDynamicLinksModuleName)); - } - SetListener(nullptr); - invites::internal::InvitesReceiverInternal::DestroyInstance( - g_receiver, g_cached_receiver); - g_receiver = nullptr; - delete g_cached_receiver; - g_cached_receiver = nullptr; -} - -Listener* SetListener(Listener* listener) { - if (g_cached_receiver == nullptr) return nullptr; - - if (listener) { - Fetch(); - } - - return g_cached_receiver->SetListener(listener); -} - -void Fetch() { - if (g_receiver) g_receiver->Fetch(); -} - -} // namespace dynamic_links -} // namespace firebase diff --git a/dynamic_links/src/common.h b/dynamic_links/src/common.h deleted file mode 100644 index 290f4497d3..0000000000 --- a/dynamic_links/src/common.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef FIREBASE_DYNAMIC_LINKS_SRC_COMMON_H_ -#define FIREBASE_DYNAMIC_LINKS_SRC_COMMON_H_ - -#include "app/src/include/firebase/app.h" -#include "app/src/reference_counted_future_impl.h" -#include "dynamic_links/src/include/firebase/dynamic_links.h" - -namespace firebase { -namespace dynamic_links { - -enum DynamicLinksFn { kDynamicLinksFnGetShortLink, kDynamicLinksFnCount }; - -// Data structure which holds the Future API implementation with the -// future required by this API. -class FutureData { - public: - FutureData() : api_(kDynamicLinksFnCount) {} - ~FutureData() {} - - ReferenceCountedFutureImpl* api() { return &api_; } - - // Create the FutureData singleton. - static FutureData* Create(); - // Destroy the FutureData singleton. - static void Destroy(); - // Get the FutureData singleton. - static FutureData* Get(); - - private: - ReferenceCountedFutureImpl api_; - - static FutureData* s_future_data_; -}; - -// Create the dynamic links receiver. -bool CreateReceiver(const App& app); -// Destroy the dynamic links receiver. -void DestroyReceiver(); - -} // namespace dynamic_links -} // namespace firebase - -#endif // FIREBASE_DYNAMIC_LINKS_SRC_COMMON_H_ diff --git a/dynamic_links/src/dynamic_links_android.cc b/dynamic_links/src/dynamic_links_android.cc deleted file mode 100644 index a0a8fb328d..0000000000 --- a/dynamic_links/src/dynamic_links_android.cc +++ /dev/null @@ -1,1019 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "app/src/assert.h" -#include "app/src/include/firebase/app.h" -#include "app/src/include/firebase/internal/common.h" -#include "app/src/include/firebase/version.h" -#include "app/src/reference_counted_future_impl.h" -#include "app/src/util.h" -#include "app/src/util_android.h" -#include "dynamic_links/src/common.h" -#include "dynamic_links/src/include/firebase/dynamic_links.h" -#include "dynamic_links/src/include/firebase/dynamic_links/components.h" - -namespace firebase { -namespace dynamic_links { - -DEFINE_FIREBASE_VERSION_STRING(FirebaseDynamicLinks); - -// Methods of the FirebaseDynamicLinks class. -// clang-format off -#define DYNAMIC_LINKS_METHODS(X) \ - X(GetInstance, "getInstance", \ - "()Lcom/google/firebase/dynamiclinks/FirebaseDynamicLinks;", \ - util::kMethodTypeStatic), \ - X(GetDynamicLinkFromIntent, "getDynamicLink", \ - "(Landroid/content/Intent;)Lcom/google/android/gms/tasks/Task;"), \ - X(GetDynamicLinkFromUri, "getDynamicLink", \ - "(Landroid/net/Uri;)Lcom/google/android/gms/tasks/Task;"), \ - X(CreateDynamicLink, "createDynamicLink", \ - "()Lcom/google/firebase/dynamiclinks/DynamicLink$Builder;") -// clang-format on - -METHOD_LOOKUP_DECLARATION(dynamic_links, DYNAMIC_LINKS_METHODS) -METHOD_LOOKUP_DEFINITION( - dynamic_links, - PROGUARD_KEEP_CLASS "com/google/firebase/dynamiclinks/FirebaseDynamicLinks", - DYNAMIC_LINKS_METHODS) - -// Methods of the DynamicLink class. -// clang-format off -#define DLINK_METHODS(X) \ - X(GetUri, "getUri", "()Landroid/net/Uri;") -// clang-format on - -METHOD_LOOKUP_DECLARATION(dlink, DLINK_METHODS) -METHOD_LOOKUP_DEFINITION(dlink, - PROGUARD_KEEP_CLASS - "com/google/firebase/dynamiclinks/DynamicLink", - DLINK_METHODS) - -// Methods of the DynamicLink.Builder class. -// clang-format off -#define DLINK_BUILDER_METHODS(X) \ - X(SetLongLink, "setLongLink", \ - "(Landroid/net/Uri;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$Builder;"), \ - X(SetLink, "setLink", \ - "(Landroid/net/Uri;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$Builder;"), \ - X(SetDomainUriPrefix, "setDomainUriPrefix", \ - "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$Builder;"), \ - X(SetAndroidParameters, "setAndroidParameters", \ - "(Lcom/google/firebase/dynamiclinks/DynamicLink$AndroidParameters;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$Builder;"), \ - X(SetIosParameters, "setIosParameters", \ - "(Lcom/google/firebase/dynamiclinks/DynamicLink$IosParameters;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$Builder;"), \ - X(SetGoogleAnalyticsParameters, "setGoogleAnalyticsParameters", \ - "(Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "GoogleAnalyticsParameters;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$Builder;"), \ - X(SetItunesConnectAnalyticsParameters, \ - "setItunesConnectAnalyticsParameters", \ - "(Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "ItunesConnectAnalyticsParameters;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$Builder;"), \ - X(SetSocialMetaTagParameters, "setSocialMetaTagParameters", \ - "(Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "SocialMetaTagParameters;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$Builder;"), \ - X(BuildDynamicLink, "buildDynamicLink", \ - "()Lcom/google/firebase/dynamiclinks/DynamicLink;"), \ - X(BuildShortDynamicLink, "buildShortDynamicLink", \ - "()Lcom/google/android/gms/tasks/Task;"), \ - X(BuildShortDynamicLinkWithOption, "buildShortDynamicLink", \ - "(I)Lcom/google/android/gms/tasks/Task;") -// clang-format on - -METHOD_LOOKUP_DECLARATION(dlink_builder, DLINK_BUILDER_METHODS) -METHOD_LOOKUP_DEFINITION(dlink_builder, - PROGUARD_KEEP_CLASS - "com/google/firebase/dynamiclinks/DynamicLink$Builder", - DLINK_BUILDER_METHODS) - -// Methods of the DynamicLink.AndroidParameters.Builder class. -// clang-format off -#define DLINK_ANDROID_PARAMS_BUILDER_METHODS(X) \ - X(Constructor, "", "()V"), \ - X(ConstructorFromPackageName, "", "(Ljava/lang/String;)V"), \ - X(SetFallbackUrl, "setFallbackUrl", \ - "(Landroid/net/Uri;)Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "AndroidParameters$Builder;"), \ - X(SetMinimumVersion, "setMinimumVersion", \ - "(I)Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "AndroidParameters$Builder;"), \ - X(Build, "build", "()Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "AndroidParameters;") -// clang-format on - -METHOD_LOOKUP_DECLARATION(dlink_android_params_builder, - DLINK_ANDROID_PARAMS_BUILDER_METHODS) -METHOD_LOOKUP_DEFINITION( - dlink_android_params_builder, - PROGUARD_KEEP_CLASS - "com/google/firebase/dynamiclinks/DynamicLink$AndroidParameters$Builder", - DLINK_ANDROID_PARAMS_BUILDER_METHODS) - -// Methods of the DynamicLink.GoogleAnalyticsParameters.Builder class. -// clang-format off -#define DLINK_GOOGLE_ANALYTICS_PARAMATERS_BUILDER_METHODS(X) \ - X(Constructor, "", "()V"), \ - X(SetSource, "setSource", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "GoogleAnalyticsParameters$Builder;"), \ - X(SetMedium, "setMedium", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "GoogleAnalyticsParameters$Builder;"), \ - X(SetCampaign, "setCampaign", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "GoogleAnalyticsParameters$Builder;"), \ - X(SetTerm, "setTerm", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "GoogleAnalyticsParameters$Builder;"), \ - X(SetContent, "setContent", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "GoogleAnalyticsParameters$Builder;"), \ - X(Build, "build", "()Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "GoogleAnalyticsParameters;") -// clang-format on - -METHOD_LOOKUP_DECLARATION(dlink_google_analytics_params_builder, - DLINK_GOOGLE_ANALYTICS_PARAMATERS_BUILDER_METHODS) -METHOD_LOOKUP_DEFINITION(dlink_google_analytics_params_builder, - PROGUARD_KEEP_CLASS - "com/google/firebase/dynamiclinks/DynamicLink$" - "GoogleAnalyticsParameters$Builder", - DLINK_GOOGLE_ANALYTICS_PARAMATERS_BUILDER_METHODS) - -// Methods of the DynamicLink.IosParameters.Builder class. -// clang-format off -#define DLINK_IOS_PARAMETERS_BUILDER_METHODS(X) \ - X(Constructor, "", "(Ljava/lang/String;)V"), \ - X(SetFallbackUrl, "setFallbackUrl", "(Landroid/net/Uri;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$IosParameters$Builder;"), \ - X(SetCustomScheme, "setCustomScheme", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$IosParameters$Builder;"), \ - X(SetIpadFallbackUrl, "setIpadFallbackUrl", "(Landroid/net/Uri;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$IosParameters$Builder;"), \ - X(SetIpadBundleId, "setIpadBundleId", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$IosParameters$Builder;"), \ - X(SetAppStoreId, "setAppStoreId", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$IosParameters$Builder;"), \ - X(SetMinimumVersion, "setMinimumVersion", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$IosParameters$Builder;"), \ - X(Build, "build", \ - "()Lcom/google/firebase/dynamiclinks/DynamicLink$IosParameters;") -// clang-format on - -METHOD_LOOKUP_DECLARATION(dlink_ios_params_builder, - DLINK_IOS_PARAMETERS_BUILDER_METHODS) -METHOD_LOOKUP_DEFINITION( - dlink_ios_params_builder, - PROGUARD_KEEP_CLASS - "com/google/firebase/dynamiclinks/DynamicLink$IosParameters$Builder", - DLINK_IOS_PARAMETERS_BUILDER_METHODS) - -// Methods of the DynamicLink.ItunesConnectAnalyticsParameters.Builder class. -// clang-format off -#define DLINK_ITUNES_CONNECT_PARAMETERS_BUILDER_METHODS(X) \ - X(Constructor, "", "()V"), \ - X(SetProviderToken, "setProviderToken", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "ItunesConnectAnalyticsParameters$Builder;"), \ - X(SetAffiliateToken, "setAffiliateToken", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "ItunesConnectAnalyticsParameters$Builder;"), \ - X(SetCampaignToken, "setCampaignToken", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "ItunesConnectAnalyticsParameters$Builder;"), \ - X(Build, "build", "()Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "ItunesConnectAnalyticsParameters;") -// clang-format on - -METHOD_LOOKUP_DECLARATION(dlink_itunes_params_builder, - DLINK_ITUNES_CONNECT_PARAMETERS_BUILDER_METHODS) -METHOD_LOOKUP_DEFINITION(dlink_itunes_params_builder, - PROGUARD_KEEP_CLASS - "com/google/firebase/dynamiclinks/DynamicLink$" - "ItunesConnectAnalyticsParameters$Builder", - DLINK_ITUNES_CONNECT_PARAMETERS_BUILDER_METHODS) - -// Methods of the DynamicLink.SocialMetaTagParameters.Builder class. -// clang-format off -#define DLINK_SOCIAL_META_TAG_PARAMETERS_BUILDER_METHODS(X) \ - X(Constructor, "", "()V"), \ - X(SetTitle, "setTitle", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "SocialMetaTagParameters$Builder;"), \ - X(SetDescription, "setDescription", "(Ljava/lang/String;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "SocialMetaTagParameters$Builder;"), \ - X(SetImageUrl, "setImageUrl", "(Landroid/net/Uri;)" \ - "Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "SocialMetaTagParameters$Builder;"), \ - X(Build, "build", "()Lcom/google/firebase/dynamiclinks/DynamicLink$" \ - "SocialMetaTagParameters;") -// clang-format on - -METHOD_LOOKUP_DECLARATION(dlink_social_meta_params_builder, - DLINK_SOCIAL_META_TAG_PARAMETERS_BUILDER_METHODS) -METHOD_LOOKUP_DEFINITION(dlink_social_meta_params_builder, - PROGUARD_KEEP_CLASS - "com/google/firebase/dynamiclinks/DynamicLink$" - "SocialMetaTagParameters$Builder", - DLINK_SOCIAL_META_TAG_PARAMETERS_BUILDER_METHODS) - -// Methods of the PendingDynamicLinkData class. -// clang-format off -#define PENDING_DYNAMIC_LINK_DATA_METHODS(X) \ - X(GetLink, "getLink", "()Landroid/net/Uri;"), \ - X(GetMinimumAppVersion, "getMinimumAppVersion", "()I"), \ - X(GetClickTimestamp, "getClickTimestamp", "()J"), \ - X(GetUpdateAppIntent, "getUpdateAppIntent", \ - "(Landroid/content/Context;)Landroid/content/Intent;") -// clang-format on - -METHOD_LOOKUP_DECLARATION(pending_dynamic_link_data, - PENDING_DYNAMIC_LINK_DATA_METHODS) -METHOD_LOOKUP_DEFINITION( - pending_dynamic_link_data, - PROGUARD_KEEP_CLASS - "com/google/firebase/dynamiclinks/PendingDynamicLinkData", - PENDING_DYNAMIC_LINK_DATA_METHODS) - -// Methods of the ShortDynamicLink interface. -// clang-format off -#define SHORT_DYNAMIC_LINK_METHODS(X) \ - X(GetShortLink, "getShortLink", "()Landroid/net/Uri;"), \ - X(GetPreviewLink, "getPreviewLink", "()Landroid/net/Uri;"), \ - X(GetWarnings, "getWarnings", "()Ljava/util/List;") -// clang-format on - -METHOD_LOOKUP_DECLARATION(short_dynamic_link, SHORT_DYNAMIC_LINK_METHODS) -METHOD_LOOKUP_DEFINITION(short_dynamic_link, - PROGUARD_KEEP_CLASS - "com/google/firebase/dynamiclinks/ShortDynamicLink", - SHORT_DYNAMIC_LINK_METHODS) - -// Methods of the ShortDynamicLinkWarning interface. -// clang-format off -#define SHORT_DYNAMIC_LINK_WARNING_METHODS(X) \ - X(GetCode, "getCode", "()Ljava/lang/String;"), \ - X(GetMessage, "getMessage", "()Ljava/lang/String;") -// clang-format on - -METHOD_LOOKUP_DECLARATION(short_dynamic_link_warning, - SHORT_DYNAMIC_LINK_WARNING_METHODS) -METHOD_LOOKUP_DEFINITION( - short_dynamic_link_warning, - PROGUARD_KEEP_CLASS - "com/google/firebase/dynamiclinks/ShortDynamicLink$Warning", - SHORT_DYNAMIC_LINK_WARNING_METHODS) - -// Fields of the ShortDynamicLink$Suffix interface. -// clang-format off -#define SHORT_DYNAMIC_LINK_SUFFIX_FIELDS(X) \ - X(Unguessable, "UNGUESSABLE", "I", util::kFieldTypeStatic), \ - X(Short, "SHORT", "I", util::kFieldTypeStatic) -// clang-format on - -METHOD_LOOKUP_DECLARATION(short_dynamic_link_suffix, METHOD_LOOKUP_NONE, - SHORT_DYNAMIC_LINK_SUFFIX_FIELDS) -METHOD_LOOKUP_DEFINITION( - short_dynamic_link_suffix, - PROGUARD_KEEP_CLASS - "com/google/firebase/dynamiclinks/ShortDynamicLink$Suffix", - METHOD_LOOKUP_NONE, SHORT_DYNAMIC_LINK_SUFFIX_FIELDS) - -// Map c++ PathLength constants to java path length constants. -static struct { - PathLength path_length_code; - short_dynamic_link_suffix::Field java_path_length_field; - jint value; -} g_path_length_codes[] = { - {kPathLengthShort, short_dynamic_link_suffix::kShort}, - {kPathLengthUnguessable, short_dynamic_link_suffix::kUnguessable}, -}; - -// Global reference to the Android FirebaseDynamicLinks class instance. -// This is initialized in dynamic_links::Initialize() and never released -// during the lifetime of the application. -static jobject g_dynamic_links_class_instance = nullptr; - -// Used to retrieve the JNI environment in order to call methods on the -// Android Analytics class. -static const ::firebase::App* g_app = nullptr; - -static const char* kApiIdentifier = "Dynamic Links"; - -static void ReleaseClasses(JNIEnv* env) { - dynamic_links::ReleaseClass(env); - dlink::ReleaseClass(env); - dlink_builder::ReleaseClass(env); - dlink_android_params_builder::ReleaseClass(env); - dlink_google_analytics_params_builder::ReleaseClass(env); - dlink_ios_params_builder::ReleaseClass(env); - dlink_itunes_params_builder::ReleaseClass(env); - dlink_social_meta_params_builder::ReleaseClass(env); - pending_dynamic_link_data::ReleaseClass(env); - short_dynamic_link::ReleaseClass(env); - short_dynamic_link_warning::ReleaseClass(env); - short_dynamic_link_suffix::ReleaseClass(env); -} - -InitResult Initialize(const App& app, Listener* listener) { - if (g_app) { - LogWarning("%s API already initialized", kApiIdentifier); - return kInitResultSuccess; - } - FIREBASE_UTIL_RETURN_FAILURE_IF_GOOGLE_PLAY_UNAVAILABLE(app); - - LogDebug("%s API Initializing", kApiIdentifier); - assert(!g_dynamic_links_class_instance); - - if (!CreateReceiver(app)) { - return kInitResultFailedMissingDependency; - } - - JNIEnv* env = app.GetJNIEnv(); - jobject activity = app.activity(); - - // Cache method pointers. - if (!(dynamic_links::CacheMethodIds(env, activity) && - dlink::CacheMethodIds(env, activity) && - dlink_builder::CacheMethodIds(env, activity) && - dlink_android_params_builder::CacheMethodIds(env, activity) && - dlink_google_analytics_params_builder::CacheMethodIds(env, activity) && - dlink_ios_params_builder::CacheMethodIds(env, activity) && - dlink_itunes_params_builder::CacheMethodIds(env, activity) && - dlink_social_meta_params_builder::CacheMethodIds(env, activity) && - pending_dynamic_link_data::CacheMethodIds(env, activity) && - short_dynamic_link::CacheMethodIds(env, activity) && - short_dynamic_link_warning::CacheMethodIds(env, activity) && - short_dynamic_link_suffix::CacheFieldIds(env, activity))) { - ReleaseClasses(env); - DestroyReceiver(); - return kInitResultFailedMissingDependency; - } - - g_app = &app; - - // Create the dynamic links class. - jclass dynamic_links_class = dynamic_links::GetClass(); - jobject dynamic_links_instance_local = env->CallStaticObjectMethod( - dynamic_links_class, - dynamic_links::GetMethodId(dynamic_links::kGetInstance)); - assert(dynamic_links_instance_local); - g_dynamic_links_class_instance = - env->NewGlobalRef(dynamic_links_instance_local); - env->DeleteLocalRef(dynamic_links_instance_local); - - // Cache PathLength codes - { - int i; - for (i = 0; i < FIREBASE_ARRAYSIZE(g_path_length_codes); ++i) { - g_path_length_codes[i].value = env->GetStaticIntField( - short_dynamic_link_suffix::GetClass(), - short_dynamic_link_suffix::GetFieldId( - g_path_length_codes[i].java_path_length_field)); - } - // The map from FieldLengths to suffix field IDs doesn't match the number of - // fields defined on the Suffix interface. - assert(i == short_dynamic_link_suffix::kFieldCount); - } - - FutureData::Create(); - SetListener(listener); - - LogInfo("%s API Initialized", kApiIdentifier); - return kInitResultSuccess; -} - -namespace internal { - -bool IsInitialized() { return g_app != nullptr; } - -} // namespace internal - -void Terminate() { - if (!g_app) { - LogWarning("%s already shut down", kApiIdentifier); - return; - } - DestroyReceiver(); - JNIEnv* env = g_app->GetJNIEnv(); - g_app = nullptr; - env->DeleteGlobalRef(g_dynamic_links_class_instance); - g_dynamic_links_class_instance = nullptr; - util::CancelCallbacks(env, kApiIdentifier); - - FutureData::Destroy(); - ReleaseClasses(env); -} - -// Creates a Uri from the string passed in and sets it on the builder using -// the builder_set_method_id. -// Deletes and clears the reference to the builder passed in. -// Returns the new builder which can be used for additional calls. -static jobject SetBuilderUri(JNIEnv* jni_env, jobject builder, - const char* value, - jmethodID builder_set_method_id) { - // The builder is null. Did you forget to take the builder result of a - // previous set call? - assert(builder); - // If there's no value to set, we can just return the original builder. - if (!value) return builder; - jobject uri_local = util::ParseUriString(jni_env, value); - jobject builder_morphed = - jni_env->CallObjectMethod(builder, builder_set_method_id, uri_local); - jni_env->DeleteLocalRef(uri_local); - jni_env->DeleteLocalRef(builder); - return builder_morphed; -} - -// Creates a jstring from the string passed in and sets it on the builder using -// the builder_set_method_id. -// Deletes and clears the reference to the builder passed in. -// Returns the new builder which can be used for additional calls. -static jobject SetBuilderString(JNIEnv* jni_env, jobject builder, - const char* value, - jmethodID builder_set_method_id) { - // The builder is null. Did you forget to take the builder result of a - // previous set call? - assert(builder); - if (!value) return builder; - jstring string_value = jni_env->NewStringUTF(value); - jobject builder_morphed = - jni_env->CallObjectMethod(builder, builder_set_method_id, string_value); - jni_env->DeleteLocalRef(string_value); - jni_env->DeleteLocalRef(builder); - return builder_morphed; -} - -// Sets an object reference on a builder -static jobject SetBuilderObject(JNIEnv* jni_env, jobject builder, jobject obj, - jmethodID builder_set_method_id) { - // The builder is null. Did you forget to take the builder result of a - // previous set call? - assert(builder); - jobject builder_morphed = - jni_env->CallObjectMethod(builder, builder_set_method_id, obj); - jni_env->DeleteLocalRef(builder); - return builder_morphed; -} - -// Sets a native type on the builder using the builder_set_method_id. -// T should be cast to the appropriate base java type: -// jboolean, jbyte, jchar, jshort, jint, jlong, jfloat, jdouble -// This is mainly to help all the builder calls be consistent. -// Deletes and clears the reference to the builder passed in. -// Returns the new builder which can be used for additional calls. -template -static jobject SetBuilderBaseType(JNIEnv* jni_env, jobject builder, T arg, - jmethodID builder_set_method_id) { - // The builder is null. Did you forget to take the builder result of a - // previous set call? - assert(builder); - jobject builder_morphed = - jni_env->CallObjectMethod(builder, builder_set_method_id, arg); - jni_env->DeleteLocalRef(builder); - return builder_morphed; -} - -// Calls the builder.Build function (method_id passed in). -// This also deletes the local ref to the builder. -// Returns a local ref to the constructed object. (You must call DeleteLocalRef -// on the returned object.) -static jobject BuildBuilder(JNIEnv* jni_env, jobject builder, - jmethodID builder_build_method_id) { - // The builder is null. Did you forget to take the builder result of a - // previous set call? - assert(builder); - jobject built_obj = - jni_env->CallObjectMethod(builder, builder_build_method_id); - jni_env->DeleteLocalRef(builder); - return built_obj; -} - -// You must call DeleteLocalRef on the returned object. -static jobject CreateAndroidParameters(JNIEnv* jni_env, - const AndroidParameters& params, - std::string* error_out) { - if (!params.package_name || !*params.package_name) { - *error_out = "Android Package Name is missing."; - return nullptr; - } - - jstring package_name_local = jni_env->NewStringUTF(params.package_name); - jobject builder = jni_env->NewObject( - dlink_android_params_builder::GetClass(), - dlink_android_params_builder::GetMethodId( - dlink_android_params_builder::kConstructorFromPackageName), - package_name_local); - jni_env->DeleteLocalRef(package_name_local); - - if (params.fallback_url) { - builder = SetBuilderUri(jni_env, builder, params.fallback_url, - dlink_android_params_builder::GetMethodId( - dlink_android_params_builder::kSetFallbackUrl)); - } - builder = - SetBuilderBaseType(jni_env, builder, (jint)params.minimum_version, - dlink_android_params_builder::GetMethodId( - dlink_android_params_builder::kSetMinimumVersion)); - return BuildBuilder(jni_env, builder, - dlink_android_params_builder::GetMethodId( - dlink_android_params_builder::kBuild)); -} - -// You must call DeleteLocalRef on the returned object. -static jobject CreateGoogleAnalyticsParameters( - JNIEnv* jni_env, const GoogleAnalyticsParameters& params) { - jobject builder = jni_env->NewObject( - dlink_google_analytics_params_builder::GetClass(), - dlink_google_analytics_params_builder::GetMethodId( - dlink_google_analytics_params_builder::kConstructor)); - - builder = - SetBuilderString(jni_env, builder, params.source, - dlink_google_analytics_params_builder::GetMethodId( - dlink_google_analytics_params_builder::kSetSource)); - builder = - SetBuilderString(jni_env, builder, params.medium, - dlink_google_analytics_params_builder::GetMethodId( - dlink_google_analytics_params_builder::kSetMedium)); - builder = SetBuilderString( - jni_env, builder, params.campaign, - dlink_google_analytics_params_builder::GetMethodId( - dlink_google_analytics_params_builder::kSetCampaign)); - builder = - SetBuilderString(jni_env, builder, params.term, - dlink_google_analytics_params_builder::GetMethodId( - dlink_google_analytics_params_builder::kSetTerm)); - builder = - SetBuilderString(jni_env, builder, params.content, - dlink_google_analytics_params_builder::GetMethodId( - dlink_google_analytics_params_builder::kSetContent)); - - return BuildBuilder(jni_env, builder, - dlink_google_analytics_params_builder::GetMethodId( - dlink_google_analytics_params_builder::kBuild)); -} - -// You must call DeleteLocalRef on the returned object. -static jobject CreateIOSParameters(JNIEnv* jni_env, const IOSParameters& params, - std::string* error_out) { - if (!params.bundle_id || !*params.bundle_id) { - *error_out = "IOS Bundle ID is missing."; - return nullptr; - } - - jstring bundle_id_local = jni_env->NewStringUTF(params.bundle_id); - jobject builder = - jni_env->NewObject(dlink_ios_params_builder::GetClass(), - dlink_ios_params_builder::GetMethodId( - dlink_ios_params_builder::kConstructor), - bundle_id_local); - jni_env->DeleteLocalRef(bundle_id_local); - - builder = SetBuilderUri(jni_env, builder, params.fallback_url, - dlink_ios_params_builder::GetMethodId( - dlink_ios_params_builder::kSetFallbackUrl)); - builder = SetBuilderString(jni_env, builder, params.custom_scheme, - dlink_ios_params_builder::GetMethodId( - dlink_ios_params_builder::kSetCustomScheme)); - builder = SetBuilderUri(jni_env, builder, params.ipad_fallback_url, - dlink_ios_params_builder::GetMethodId( - dlink_ios_params_builder::kSetIpadFallbackUrl)); - builder = SetBuilderString(jni_env, builder, params.ipad_bundle_id, - dlink_ios_params_builder::GetMethodId( - dlink_ios_params_builder::kSetIpadBundleId)); - builder = SetBuilderString(jni_env, builder, params.app_store_id, - dlink_ios_params_builder::GetMethodId( - dlink_ios_params_builder::kSetAppStoreId)); - builder = SetBuilderString(jni_env, builder, params.minimum_version, - dlink_ios_params_builder::GetMethodId( - dlink_ios_params_builder::kSetMinimumVersion)); - - return BuildBuilder( - jni_env, builder, - dlink_ios_params_builder::GetMethodId(dlink_ios_params_builder::kBuild)); -} - -// You must call DeleteLocalRef on the returned object. -static jobject CreateItunesAnalyticsParameters( - JNIEnv* jni_env, const ITunesConnectAnalyticsParameters& params) { - jobject builder = - jni_env->NewObject(dlink_itunes_params_builder::GetClass(), - dlink_itunes_params_builder::GetMethodId( - dlink_itunes_params_builder::kConstructor)); - - builder = - SetBuilderString(jni_env, builder, params.provider_token, - dlink_itunes_params_builder::GetMethodId( - dlink_itunes_params_builder::kSetProviderToken)); - builder = - SetBuilderString(jni_env, builder, params.affiliate_token, - dlink_itunes_params_builder::GetMethodId( - dlink_itunes_params_builder::kSetAffiliateToken)); - builder = - SetBuilderString(jni_env, builder, params.campaign_token, - dlink_itunes_params_builder::GetMethodId( - dlink_itunes_params_builder::kSetCampaignToken)); - - return BuildBuilder(jni_env, builder, - dlink_itunes_params_builder::GetMethodId( - dlink_itunes_params_builder::kBuild)); -} - -// You must call DeleteLocalRef on the returned object. -static jobject CreateSocalMetaParameters( - JNIEnv* jni_env, const SocialMetaTagParameters& params) { - jobject builder = - jni_env->NewObject(dlink_social_meta_params_builder::GetClass(), - dlink_social_meta_params_builder::GetMethodId( - dlink_social_meta_params_builder::kConstructor)); - - builder = SetBuilderString(jni_env, builder, params.title, - dlink_social_meta_params_builder::GetMethodId( - dlink_social_meta_params_builder::kSetTitle)); - builder = - SetBuilderString(jni_env, builder, params.description, - dlink_social_meta_params_builder::GetMethodId( - dlink_social_meta_params_builder::kSetDescription)); - builder = SetBuilderUri(jni_env, builder, params.image_url, - dlink_social_meta_params_builder::GetMethodId( - dlink_social_meta_params_builder::kSetImageUrl)); - - return BuildBuilder(jni_env, builder, - dlink_social_meta_params_builder::GetMethodId( - dlink_social_meta_params_builder::kBuild)); -} - -// You must call DeleteLocalRef on the returned object. -// if there is an error, error_out will be written and jobject will be nullptr. -static jobject PopulateLinkBuilder(JNIEnv* jni_env, - const DynamicLinkComponents& components, - std::string* error_out) { - assert(error_out != nullptr); - if (!components.link || !*components.link) { - *error_out = "Link is missing."; - return nullptr; - } - if (!components.domain_uri_prefix || !*components.domain_uri_prefix) { - *error_out = - "DynamicLinkComponents.domain_uri_prefix is required and cannot be " - "empty."; - return nullptr; - } - - jobject link_builder = jni_env->CallObjectMethod( - g_dynamic_links_class_instance, - dynamic_links::GetMethodId(dynamic_links::kCreateDynamicLink)); - - link_builder = - SetBuilderUri(jni_env, link_builder, components.link, - dlink_builder::GetMethodId(dlink_builder::kSetLink)); - *error_out = util::GetAndClearExceptionMessage(jni_env); - if (error_out->size()) { - // setLink() threw an exception. - jni_env->DeleteLocalRef(link_builder); - return nullptr; - } - - link_builder = SetBuilderString( - jni_env, link_builder, components.domain_uri_prefix, - dlink_builder::GetMethodId(dlink_builder::kSetDomainUriPrefix)); - *error_out = util::GetAndClearExceptionMessage(jni_env); - if (error_out->size()) { - // setDomainUriPrefix() threw an exception. - jni_env->DeleteLocalRef(link_builder); - return nullptr; - } - - if (components.android_parameters) { - jobject android_parameters_local = CreateAndroidParameters( - jni_env, *components.android_parameters, error_out); - if (!android_parameters_local) { - // some required inputs were missing. - jni_env->DeleteLocalRef(link_builder); - return nullptr; - } - - link_builder = SetBuilderObject( - jni_env, link_builder, android_parameters_local, - dlink_builder::GetMethodId(dlink_builder::kSetAndroidParameters)); - jni_env->DeleteLocalRef(android_parameters_local); - } - - // GoogleAnalyticsParameters - if (components.google_analytics_parameters) { - jobject google_analytics_parameters_local = CreateGoogleAnalyticsParameters( - jni_env, *components.google_analytics_parameters); - // There no required parameters, so no exceptions or errors to find here. - link_builder = SetBuilderObject( - jni_env, link_builder, google_analytics_parameters_local, - dlink_builder::GetMethodId( - dlink_builder::kSetGoogleAnalyticsParameters)); - jni_env->DeleteLocalRef(google_analytics_parameters_local); - } - - // IOSParameters - if (components.ios_parameters) { - jobject ios_parameters_local = - CreateIOSParameters(jni_env, *components.ios_parameters, error_out); - if (!ios_parameters_local) { - // some required inputs were missing. - jni_env->DeleteLocalRef(link_builder); - return nullptr; - } - link_builder = SetBuilderObject( - jni_env, link_builder, ios_parameters_local, - dlink_builder::GetMethodId(dlink_builder::kSetIosParameters)); - jni_env->DeleteLocalRef(ios_parameters_local); - } - - // ITunesConnectAnalyticsParameters - if (components.itunes_connect_analytics_parameters) { - jobject itunes_analytics_parameters_local = CreateItunesAnalyticsParameters( - jni_env, *components.itunes_connect_analytics_parameters); - // There no required parameters, so no exceptions or errors to find here. - link_builder = SetBuilderObject( - jni_env, link_builder, itunes_analytics_parameters_local, - dlink_builder::GetMethodId( - dlink_builder::kSetItunesConnectAnalyticsParameters)); - jni_env->DeleteLocalRef(itunes_analytics_parameters_local); - } - - // SocialMetaTagParameters - if (components.social_meta_tag_parameters) { - jobject social_meta_parameters_local = CreateSocalMetaParameters( - jni_env, *components.social_meta_tag_parameters); - // There no required parameters, so no exceptions or errors to find here. - link_builder = SetBuilderObject( - jni_env, link_builder, social_meta_parameters_local, - dlink_builder::GetMethodId(dlink_builder::kSetSocialMetaTagParameters)); - jni_env->DeleteLocalRef(social_meta_parameters_local); - } - - return link_builder; -} - -static jobject PopulateLinkBuilder(JNIEnv* jni_env, const char* long_link, - std::string* error_out) { - jobject link_builder = jni_env->CallObjectMethod( - g_dynamic_links_class_instance, - dynamic_links::GetMethodId(dynamic_links::kCreateDynamicLink)); - *error_out = util::GetAndClearExceptionMessage(jni_env); - if (error_out->size()) { - jni_env->DeleteLocalRef(link_builder); - return nullptr; - } - - link_builder = - SetBuilderUri(jni_env, link_builder, long_link, - dlink_builder::GetMethodId(dlink_builder::kSetLongLink)); - - return link_builder; -} - -// Converts a `java.util.List` to a `std::vector`, where -// Warning contains 2 strings, one for the warning code and one for the message. -// These are concatenated together in the form ": ". -void JavaWarningListToStdStringVector(JNIEnv* env, - std::vector* vector, - jobject java_list_obj) { - int size = env->CallIntMethod(java_list_obj, - util::list::GetMethodId(util::list::kSize)); - vector->clear(); - vector->reserve(size); - for (int i = 0; i < size; i++) { - jobject warning_element = env->CallObjectMethod( - java_list_obj, util::list::GetMethodId(util::list::kGet), i); - - jobject code_string_local = env->CallObjectMethod( - warning_element, short_dynamic_link_warning::GetMethodId( - short_dynamic_link_warning::kGetCode)); - jobject message_string_local = env->CallObjectMethod( - warning_element, short_dynamic_link_warning::GetMethodId( - short_dynamic_link_warning::kGetMessage)); - - env->DeleteLocalRef(warning_element); - - // these consume the local ref. - std::string code = util::JniStringToString(env, code_string_local); - std::string msg = util::JniStringToString(env, message_string_local); - - vector->push_back(code + ": " + msg); - } -} - -GeneratedDynamicLink GetLongLink(const DynamicLinkComponents& components) { - GeneratedDynamicLink gen_link; - FIREBASE_ASSERT_RETURN(gen_link, internal::IsInitialized()); - - JNIEnv* jni_env = g_app->GetJNIEnv(); - jobject link_builder = - PopulateLinkBuilder(jni_env, components, &gen_link.error); - if (!link_builder) { - return gen_link; - } - - jobject dlink_local = jni_env->CallObjectMethod( - link_builder, - dlink_builder::GetMethodId(dlink_builder::kBuildDynamicLink)); - gen_link.error = util::GetAndClearExceptionMessage(jni_env); - if (gen_link.error.size()) { - jni_env->DeleteLocalRef(dlink_local); - jni_env->DeleteLocalRef(link_builder); - return gen_link; - } - - jobject uri_local = jni_env->CallObjectMethod( - dlink_local, dlink::GetMethodId(dlink::kGetUri)); - gen_link.error = util::GetAndClearExceptionMessage(jni_env); - if (gen_link.error.size()) { - jni_env->DeleteLocalRef(uri_local); - jni_env->DeleteLocalRef(dlink_local); - jni_env->DeleteLocalRef(link_builder); - return gen_link; - } - - gen_link.url = util::JniUriToString(jni_env, uri_local); - - jni_env->DeleteLocalRef(dlink_local); - jni_env->DeleteLocalRef(link_builder); - return gen_link; -} - -static void FutureShortLinkCallback(JNIEnv* jni_env, jobject result, - util::FutureResult result_code, - const char* status_message, - void* callback_data) { - if (result_code == util::kFutureResultSuccess) { - // There should only one type that this callback currently handles on - // success. - assert(jni_env->IsInstanceOf(result, short_dynamic_link::GetClass())); - - GeneratedDynamicLink result_link; - - jobject uri_local = jni_env->CallObjectMethod( - result, - short_dynamic_link::GetMethodId(short_dynamic_link::kGetShortLink)); - result_link.url = util::JniUriToString(jni_env, uri_local); - - jobject warnings_list_local = jni_env->CallObjectMethod( - result, - short_dynamic_link::GetMethodId(short_dynamic_link::kGetWarnings)); - if (warnings_list_local != nullptr) { - // TODO(butterfield): NOTE: Currently the Java code does not return any - // warnings, so this code is untested! - JavaWarningListToStdStringVector(jni_env, &result_link.warnings, - warnings_list_local); - jni_env->DeleteLocalRef(warnings_list_local); - } - - FutureData* future_data = FutureData::Get(); - if (future_data) { - future_data->api()->CompleteWithResult( - FutureHandle(reinterpret_cast(callback_data)), - kErrorCodeSuccess, result_link); - } - } else { // result_code != Success - GeneratedDynamicLink result_link; - FutureData* future_data = FutureData::Get(); - if (future_data) { - result_link.error = status_message; - future_data->api()->CompleteWithResult( - FutureHandle(reinterpret_cast(callback_data)), - kErrorCodeFailed, status_message, result_link); - } - } -} - -static jint GetSuffixOption(const PathLength& path_length) { - for (int i = 0; i < FIREBASE_ARRAYSIZE(g_path_length_codes); ++i) { - if (g_path_length_codes[i].path_length_code == path_length) - return g_path_length_codes[i].value; - } - // Couldn't find the value in the map, must be default. - return kPathLengthDefault; -} - -// Common code for short links to set up the callback to handle the result. -static Future HandleShortLinkTask( - JNIEnv* jni_env, jobject link_builder, - const DynamicLinkOptions& dynamic_link_options, const std::string& error) { - ReferenceCountedFutureImpl* api = FutureData::Get()->api(); - const SafeFutureHandle handle = - api->SafeAlloc(kDynamicLinksFnGetShortLink); - - if (!link_builder) { - GeneratedDynamicLink gen_link; - gen_link.error = error; - api->CompleteWithResult(handle, kErrorCodeFailed, error.c_str(), gen_link); - return MakeFuture(api, handle); - } - jobject task; - if (dynamic_link_options.path_length != kPathLengthDefault) { - task = jni_env->CallObjectMethod( - link_builder, - dlink_builder::GetMethodId( - dlink_builder::kBuildShortDynamicLinkWithOption), - GetSuffixOption(dynamic_link_options.path_length)); - } else { - task = jni_env->CallObjectMethod( - link_builder, - dlink_builder::GetMethodId(dlink_builder::kBuildShortDynamicLink)); - } - - std::string exception_message = util::GetAndClearExceptionMessage(jni_env); - if (exception_message.size()) { - GeneratedDynamicLink gen_link; - gen_link.error = exception_message; - LogError("Couldn't build short link: %s", exception_message.c_str()); - api->CompleteWithResult(handle, kErrorCodeFailed, exception_message.c_str(), - gen_link); - } else { - util::RegisterCallbackOnTask(jni_env, task, FutureShortLinkCallback, - reinterpret_cast(handle.get().id()), - kApiIdentifier); - } - - jni_env->DeleteLocalRef(link_builder); - jni_env->DeleteLocalRef(task); - return MakeFuture(api, handle); -} - -Future GetShortLink( - const DynamicLinkComponents& components, - const DynamicLinkOptions& options) { - FIREBASE_ASSERT_RETURN(Future(), - internal::IsInitialized()); - JNIEnv* jni_env = g_app->GetJNIEnv(); - - // Temporary workaround: Get short link from long link rather than from - // components. TODO(b/113628371): remove this when the "Error 8" bug is fixed. - // - // First, get the long link. If that returns an error, pass that error and - // a null link builder to HandleShortLinkTask(), which will return a Future - // that propagates the error to the caller. - // - // If there was no error getting the long link, PopulateLinkBuilder handles - // getting the short link the same way that GetShortLink(long_link) does. - GeneratedDynamicLink long_link = GetLongLink(components); - std::string error = long_link.error; - jobject link_builder = nullptr; - if (error.empty()) { - link_builder = PopulateLinkBuilder(jni_env, long_link.url.c_str(), &error); - } - return HandleShortLinkTask(jni_env, link_builder, options, error); -} - -Future GetShortLink( - const DynamicLinkComponents& components) { - return GetShortLink(components, DynamicLinkOptions()); -} - -Future GetShortLink(const char* long_dynamic_link, - const DynamicLinkOptions& options) { - FIREBASE_ASSERT_RETURN(Future(), - internal::IsInitialized()); - JNIEnv* jni_env = g_app->GetJNIEnv(); - std::string error; - jobject link_builder = - PopulateLinkBuilder(jni_env, long_dynamic_link, &error); - return HandleShortLinkTask(jni_env, link_builder, options, error); -} - -Future GetShortLink(const char* long_dynamic_link) { - return GetShortLink(long_dynamic_link, DynamicLinkOptions()); -} - -Future GetShortLinkLastResult() { - FIREBASE_ASSERT_RETURN(Future(), - internal::IsInitialized()); - ReferenceCountedFutureImpl* api = FutureData::Get()->api(); - return static_cast&>( - api->LastResult(kDynamicLinksFnGetShortLink)); -} - -} // namespace dynamic_links -} // namespace firebase diff --git a/dynamic_links/src/dynamic_links_ios.mm b/dynamic_links/src/dynamic_links_ios.mm deleted file mode 100644 index 5e707fcfa7..0000000000 --- a/dynamic_links/src/dynamic_links_ios.mm +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "dynamic_links/src/include/firebase/dynamic_links.h" -#include "dynamic_links/src/include/firebase/dynamic_links/components.h" - -#include "FDLURLComponents.h" - -#include "app/src/assert.h" -#include "app/src/include/firebase/variant.h" -#include "app/src/include/firebase/version.h" -#include "app/src/invites/ios/invites_receiver_internal_ios.h" -#include "app/src/reference_counted_future_impl.h" -#include "app/src/util_ios.h" -#include "dynamic_links/src/common.h" - -namespace firebase { -namespace dynamic_links { - -DEFINE_FIREBASE_VERSION_STRING(FirebaseDynamicLinks); - -static invites::internal::InvitesReceiverInternalIos::StartupRegistration - g_invites_startup_registration("ddl"); -static bool g_initialized = false; -static const char* kUrlEncodingError = "Specified link could not be encoded as a URL."; - -InitResult Initialize(const App& app, Listener* listener) { - if (!g_initialized) { - invites::internal::InvitesReceiverInternalIos::RegisterStartup(&g_invites_startup_registration); - g_initialized = CreateReceiver(app); - assert(g_initialized); - FutureData::Create(); - SetListener(listener); - } - return kInitResultSuccess; -} - -namespace internal { - -bool IsInitialized() { return g_initialized; } - -} // namespace internal - -void Terminate() { - if (!g_initialized) return; - DestroyReceiver(); - FutureData::Destroy(); - g_initialized = false; -} - -// Encode a URL from a C string. If this fails, nil is returned. -static NSURL* EncodeUrlFromString(const char* url_string) { - // Try encoding without escaping as the URL may already be escaped correctly. - NSURL* url = [NSURL URLWithString:@(url_string)]; - if (url) return url; - // If encoding without escaping fails, try again with percent encoding. - return [NSURL - URLWithString:[@(url_string) stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; -} - -// Add a warning to the list of warnings regarding failure to encode the specified -// URL. -static void AddUrlEncodingWarning(std::vector* warnings, const char* url, - const char* field_description) { - warnings->push_back(std::string("Failed to encode URL for ") + std::string(field_description) + - ", URL: " + url); -} - -// Set a URL field of an iOS dynamic link components object from a C++ structure string field. -#define FIR_DYNAMIC_LINK_PARAMS_SET_URL(fir_params_object, field, cpp_params_object, cpp_field, \ - field_description, generated_link_warnings) \ - { \ - if ((cpp_params_object)->cpp_field) { \ - NSURL* ns_url = EncodeUrlFromString((cpp_params_object)->cpp_field); \ - if (ns_url) { \ - (fir_params_object).field = ns_url; \ - } else { \ - AddUrlEncodingWarning(generated_link_warnings, (cpp_params_object)->cpp_field, \ - field_description); \ - } \ - } \ - } - -// Set a string field of an iOS dynamic link components object from a C++ structure string field. -#define FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params_object, field, cpp_params_object, cpp_field) \ - { \ - if ((cpp_params_object)->cpp_field) { \ - (fir_params_object).field = @((cpp_params_object)->cpp_field); \ - } \ - } - -// Construct FIRDynamicLinkComponents and populate GeneratedDynamicLink from DynamicLinkComponents. -static FIRDynamicLinkComponents* GetFIRComponentsAndGeneratedLink( - const DynamicLinkComponents& components, GeneratedDynamicLink* generated_link) { - static const char* kMissingFieldPostfix = "must be specified"; - if (!components.link) { - generated_link->error = std::string("Link ") + kMissingFieldPostfix; - return nil; - } - if (!components.domain_uri_prefix || !*components.domain_uri_prefix) { - generated_link->error = std::string("Domain URI Prefix ") + kMissingFieldPostfix; - return nil; - } - NSURL* link_url = EncodeUrlFromString(components.link); - if (!link_url) { - generated_link->error = kUrlEncodingError; - return nil; - } - FIRDynamicLinkComponents* fir_components = - [FIRDynamicLinkComponents componentsWithLink:link_url - domainURIPrefix:@(components.domain_uri_prefix)]; - { - auto* cpp_params = components.google_analytics_parameters; - if (cpp_params) { - FIRDynamicLinkGoogleAnalyticsParameters* fir_params = - [[FIRDynamicLinkGoogleAnalyticsParameters alloc] init]; - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, source, cpp_params, source); - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, medium, cpp_params, medium); - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, campaign, cpp_params, campaign); - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, term, cpp_params, term); - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, content, cpp_params, content); - fir_components.analyticsParameters = fir_params; - } - } - { - auto* cpp_params = components.ios_parameters; - if (cpp_params) { - if (!cpp_params->bundle_id) { - generated_link->error = std::string("iOS parameters bundle ID ") + kMissingFieldPostfix; - return nil; - } - FIRDynamicLinkIOSParameters* fir_params = - [FIRDynamicLinkIOSParameters parametersWithBundleID:@(cpp_params->bundle_id)]; - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, appStoreID, cpp_params, app_store_id); - FIR_DYNAMIC_LINK_PARAMS_SET_URL(fir_params, fallbackURL, cpp_params, fallback_url, - "iOS fallback URL", &generated_link->warnings); - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, customScheme, cpp_params, custom_scheme); - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, iPadBundleID, cpp_params, ipad_bundle_id); - FIR_DYNAMIC_LINK_PARAMS_SET_URL(fir_params, iPadFallbackURL, cpp_params, ipad_fallback_url, - "iOS iPad fallback URL", &generated_link->warnings); - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, minimumAppVersion, cpp_params, - minimum_version); - fir_components.iOSParameters = fir_params; - } - } - { - auto* cpp_params = components.itunes_connect_analytics_parameters; - if (cpp_params) { - FIRDynamicLinkItunesConnectAnalyticsParameters* fir_params = - [[FIRDynamicLinkItunesConnectAnalyticsParameters alloc] init]; - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, affiliateToken, cpp_params, affiliate_token); - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, campaignToken, cpp_params, campaign_token); - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, providerToken, cpp_params, provider_token); - fir_components.iTunesConnectParameters = fir_params; - } - } - { - auto* cpp_params = components.android_parameters; - if (cpp_params) { - if (!cpp_params->package_name) { - generated_link->error = - std::string("Android parameters package name ") + kMissingFieldPostfix; - return nil; - } - FIRDynamicLinkAndroidParameters* fir_params = - [FIRDynamicLinkAndroidParameters parametersWithPackageName:@(cpp_params->package_name)]; - FIR_DYNAMIC_LINK_PARAMS_SET_URL(fir_params, fallbackURL, cpp_params, fallback_url, - "Android fallback URL", &generated_link->warnings); - fir_params.minimumVersion = cpp_params->minimum_version; - fir_components.androidParameters = fir_params; - } - } - { - auto* cpp_params = components.social_meta_tag_parameters; - if (cpp_params) { - FIRDynamicLinkSocialMetaTagParameters* fir_params = - [[FIRDynamicLinkSocialMetaTagParameters alloc] init]; - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, title, cpp_params, title); - FIR_DYNAMIC_LINK_PARAMS_SET_STRING(fir_params, descriptionText, cpp_params, description); - FIR_DYNAMIC_LINK_PARAMS_SET_URL(fir_params, imageURL, cpp_params, image_url, - "Social Image URL", &generated_link->warnings); - fir_components.socialMetaTagParameters = fir_params; - } - } - if (fir_components.url) { - generated_link->url = util::NSStringToString(fir_components.url.absoluteString); - } else { - generated_link->error = "Failed to generated long link."; - } - return fir_components; -} - -GeneratedDynamicLink GetLongLink(const DynamicLinkComponents& components) { - FIREBASE_ASSERT_RETURN(GeneratedDynamicLink(), internal::IsInitialized()); - GeneratedDynamicLink generated_link; - GetFIRComponentsAndGeneratedLink(components, &generated_link); - return generated_link; -} - -// Convert DynamicLinkOptions to FIRDynamicLinkComponentsOptions. -static FIRDynamicLinkComponentsOptions* ToFIRDynamicLinkComponentsOptions( - const DynamicLinkOptions& dynamic_link_options) { - FIRDynamicLinkComponentsOptions* fir_options = [[FIRDynamicLinkComponentsOptions alloc] init]; - switch (dynamic_link_options.path_length) { - case kPathLengthShort: - fir_options.pathLength = FIRShortDynamicLinkPathLengthShort; - break; - case kPathLengthUnguessable: - fir_options.pathLength = FIRShortDynamicLinkPathLengthUnguessable; - break; - case kPathLengthDefault: - // Drop through. - default: - fir_options.pathLength = FIRShortDynamicLinkPathLengthDefault; - break; - } - return fir_options; -} - -// Generate a short link from a long dynamic link. -static Future GetShortLink(NSURL* long_link_url, - const GeneratedDynamicLink& generated_link, - const DynamicLinkOptions& dynamic_link_options) { - FIREBASE_ASSERT_RETURN(Future(), internal::IsInitialized()); - ReferenceCountedFutureImpl* api = FutureData::Get()->api(); - const SafeFutureHandle handle = - api->SafeAlloc(kDynamicLinksFnGetShortLink); - if (long_link_url) { - GeneratedDynamicLink* output_generated_link = new GeneratedDynamicLink(); - *output_generated_link = generated_link; - [FIRDynamicLinkComponents - shortenURL:long_link_url - options:ToFIRDynamicLinkComponentsOptions(dynamic_link_options) - completion:^(NSURL* _Nullable shortURL, NSArray* _Nullable warnings, - NSError* _Nullable error) { - int error_code = kErrorCodeSuccess; - if (error) { - error_code = error.code ? static_cast(error.code) : kErrorCodeFailed; - output_generated_link->error = util::NSStringToString(error.localizedDescription); - } else { - if (warnings) { - for (NSString* warning in warnings) { - output_generated_link->warnings.push_back(warning.UTF8String); - } - } - if (shortURL) { - output_generated_link->url = util::NSStringToString(shortURL.absoluteString); - } else { - error_code = kErrorCodeFailed; - output_generated_link->error = - std::string("Failed to shorten link ") + output_generated_link->url; - } - } - FutureData::Get()->api()->CompleteWithResult( - handle, error_code, output_generated_link->error.c_str(), *output_generated_link); - delete output_generated_link; - }]; - } else { - api->CompleteWithResult(handle, kErrorCodeFailed, generated_link.error.c_str(), generated_link); - } - return MakeFuture(api, handle); -} - -Future GetShortLink(const DynamicLinkComponents& components, - const DynamicLinkOptions& dynamic_link_options) { - FIREBASE_ASSERT_RETURN(Future(), internal::IsInitialized()); - GeneratedDynamicLink generated_link; - FIRDynamicLinkComponents* fir_components = - GetFIRComponentsAndGeneratedLink(components, &generated_link); - return GetShortLink(fir_components ? fir_components.url : nil, generated_link, - dynamic_link_options); -} - -Future GetShortLink(const DynamicLinkComponents& components) { - return GetShortLink(components, DynamicLinkOptions()); -} - -Future GetShortLink(const char* long_dynamic_link, - const DynamicLinkOptions& dynamic_link_options) { - FIREBASE_ASSERT_RETURN(Future(), internal::IsInitialized()); - GeneratedDynamicLink generated_link; - NSURL* link_url = EncodeUrlFromString(long_dynamic_link); - if (!link_url) generated_link.error = kUrlEncodingError; - return GetShortLink(link_url, generated_link, dynamic_link_options); -} - -Future GetShortLink(const char* long_dynamic_link) { - return GetShortLink(long_dynamic_link, DynamicLinkOptions()); -} - -Future GetShortLinkLastResult() { - FIREBASE_ASSERT_RETURN(Future(), internal::IsInitialized()); - ReferenceCountedFutureImpl* api = FutureData::Get()->api(); - return static_cast&>( - api->LastResult(kDynamicLinksFnGetShortLink)); -} - -} // namespace dynamic_links -} // namespace firebase diff --git a/dynamic_links/src/dynamic_links_stub.cc b/dynamic_links/src/dynamic_links_stub.cc deleted file mode 100644 index a4c79333bb..0000000000 --- a/dynamic_links/src/dynamic_links_stub.cc +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include -#include -#include - -#include "app/src/assert.h" -#include "app/src/include/firebase/variant.h" -#include "app/src/include/firebase/version.h" -#include "app/src/reference_counted_future_impl.h" -#include "dynamic_links/src/common.h" -#include "dynamic_links/src/include/firebase/dynamic_links.h" -#include "dynamic_links/src/include/firebase/dynamic_links/components.h" - -namespace firebase { -namespace dynamic_links { - -DEFINE_FIREBASE_VERSION_STRING(FirebaseDynamicLinks); - -static const char* kLinkShorteningNotSupported = - "Link shortening is not supported on desktop."; - -bool g_initialized = false; - -InitResult Initialize(const App& app, Listener* listener) { - if (!g_initialized) { - g_initialized = CreateReceiver(app); - assert(g_initialized); - FutureData::Create(); - SetListener(listener); - } - return kInitResultSuccess; -} - -namespace internal { - -bool IsInitialized() { return g_initialized; } - -} // namespace internal - -void Terminate() { - if (!g_initialized) return; - DestroyReceiver(); - FutureData::Destroy(); - g_initialized = false; -} - -// Store a value (as a string) associated with the string key in the specified -// output_map. -template -void StoreKeyValuePairAsStringInMap( - std::map* output_map, const char* key, - const T value) { - (*output_map)[key] = Variant(value).AsString().mutable_string(); -} - -// Specialization of StoreKeyValuePairAsStringInMap() that ignores null strings. -template <> -void StoreKeyValuePairAsStringInMap( - std::map* output_map, const char* key, - const char* value) { - if (value) (*output_map)[key] = value; -} - -// Generate a query string from map of strings. -std::string QueryStringFromMap( - const std::map& parameters) { - std::string query_string; - int index = 0; - for (auto it = parameters.begin(); it != parameters.end(); ++it, ++index) { - const char* prefix = index == 0 ? "?" : "&"; - // TODO(smiles): URLs really need to be percent encoded. - query_string += prefix; - query_string += it->first; - query_string += "="; - query_string += it->second; - } - return query_string; -} - -// Generate a long link from dynamic links components. -static GeneratedDynamicLink LongLinkFromComponents( - const DynamicLinkComponents& components) { - GeneratedDynamicLink generated_link; - if (components.link == nullptr || strlen(components.link) == 0) { - generated_link.error = "No target link specified."; - return generated_link; - } - if (components.domain_uri_prefix == nullptr || - strlen(components.domain_uri_prefix) == 0) { - generated_link.error = "No domain specified."; - return generated_link; - } - std::map query_parameters; - StoreKeyValuePairAsStringInMap(&query_parameters, "link", components.link); - { - const auto* params = components.google_analytics_parameters; - if (params) { - StoreKeyValuePairAsStringInMap(&query_parameters, "utm_source", - params->source); - StoreKeyValuePairAsStringInMap(&query_parameters, "utm_medium", - params->medium); - StoreKeyValuePairAsStringInMap(&query_parameters, "utm_campaign", - params->campaign); - StoreKeyValuePairAsStringInMap(&query_parameters, "utm_term", - params->term); - StoreKeyValuePairAsStringInMap(&query_parameters, "utm_content", - params->content); - } - } - { - const auto* params = components.ios_parameters; - if (params) { - StoreKeyValuePairAsStringInMap(&query_parameters, "ibi", - params->bundle_id); - StoreKeyValuePairAsStringInMap(&query_parameters, "isi", - params->app_store_id); - StoreKeyValuePairAsStringInMap(&query_parameters, "ifl", - params->fallback_url); - StoreKeyValuePairAsStringInMap(&query_parameters, "ius", - params->custom_scheme); - StoreKeyValuePairAsStringInMap(&query_parameters, "imv", - params->minimum_version); - StoreKeyValuePairAsStringInMap(&query_parameters, "ipbi", - params->ipad_bundle_id); - StoreKeyValuePairAsStringInMap(&query_parameters, "ipfl", - params->ipad_fallback_url); - } - } - { - const auto* params = components.itunes_connect_analytics_parameters; - if (params) { - StoreKeyValuePairAsStringInMap(&query_parameters, "pt", - params->provider_token); - StoreKeyValuePairAsStringInMap(&query_parameters, "ct", - params->campaign_token); - StoreKeyValuePairAsStringInMap(&query_parameters, "at", - params->affiliate_token); - } - } - { - const auto* params = components.android_parameters; - if (params) { - StoreKeyValuePairAsStringInMap(&query_parameters, "apn", - params->package_name); - StoreKeyValuePairAsStringInMap(&query_parameters, "afl", - params->fallback_url); - StoreKeyValuePairAsStringInMap(&query_parameters, "amv", - params->minimum_version); - } - } - { - const auto* params = components.social_meta_tag_parameters; - if (params) { - StoreKeyValuePairAsStringInMap(&query_parameters, "st", params->title); - StoreKeyValuePairAsStringInMap(&query_parameters, "sd", - params->description); - StoreKeyValuePairAsStringInMap(&query_parameters, "si", - params->image_url); - } - } - generated_link.url = std::string(components.domain_uri_prefix) + "/" + - QueryStringFromMap(query_parameters); - return generated_link; -} - -GeneratedDynamicLink GetLongLink(const DynamicLinkComponents& components) { - FIREBASE_ASSERT_RETURN(GeneratedDynamicLink(), internal::IsInitialized()); - return LongLinkFromComponents(components); -} - -Future GetShortLink( - const DynamicLinkComponents& components, - const DynamicLinkOptions& /*dynamic_link_options*/) { - FIREBASE_ASSERT_RETURN(Future(), - internal::IsInitialized()); - auto long_link = GetLongLink(components); - long_link.warnings.push_back(kLinkShorteningNotSupported); - ReferenceCountedFutureImpl* api = FutureData::Get()->api(); - const auto handle = - api->SafeAlloc(kDynamicLinksFnGetShortLink); - api->CompleteWithResult(handle, 0, "", long_link); - return GetShortLinkLastResult(); -} - -Future GetShortLink( - const DynamicLinkComponents& components) { - return GetShortLink(components, DynamicLinkOptions()); -} - -Future GetShortLink( - const char* long_dynamic_link, - const DynamicLinkOptions& /*dynamic_link_options*/) { - FIREBASE_ASSERT_RETURN(Future(), - internal::IsInitialized()); - GeneratedDynamicLink long_link; - long_link.url = long_dynamic_link; - long_link.warnings.push_back(kLinkShorteningNotSupported); - ReferenceCountedFutureImpl* api = FutureData::Get()->api(); - const auto handle = - api->SafeAlloc(kDynamicLinksFnGetShortLink); - api->CompleteWithResult(handle, 0, "", long_link); - return GetShortLinkLastResult(); -} - -Future GetShortLink(const char* long_dynamic_link) { - return GetShortLink(long_dynamic_link, DynamicLinkOptions()); -} - -Future GetShortLinkLastResult() { - FIREBASE_ASSERT_RETURN(Future(), - internal::IsInitialized()); - ReferenceCountedFutureImpl* api = FutureData::Get()->api(); - return static_cast&>( - api->LastResult(kDynamicLinksFnGetShortLink)); -} - -} // namespace dynamic_links -} // namespace firebase diff --git a/dynamic_links/src/include/firebase/dynamic_links.h b/dynamic_links/src/include/firebase/dynamic_links.h deleted file mode 100644 index eb1bf6e47d..0000000000 --- a/dynamic_links/src/include/firebase/dynamic_links.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef FIREBASE_DYNAMIC_LINKS_SRC_INCLUDE_FIREBASE_DYNAMIC_LINKS_H_ -#define FIREBASE_DYNAMIC_LINKS_SRC_INCLUDE_FIREBASE_DYNAMIC_LINKS_H_ - -#include - -#include "firebase/app.h" -#include "firebase/internal/common.h" - -#if !defined(DOXYGEN) && !defined(SWIG) -FIREBASE_APP_REGISTER_CALLBACKS_REFERENCE(dynamic_links) -#endif // !defined(DOXYGEN) && !defined(SWIG) - -namespace firebase { - -/// @brief Firebase Dynamic Links API. -/// -/// Firebase Dynamic Links is a cross-platform solution for generating and -/// receiving links, whether or not the app is already installed. -/// -/// @deprecated Dynamic Links is now deprecated. Please see the support -/// documentation at https://firebase.google.com/support/dynamic-links-faq -/// for more information. -namespace dynamic_links { - -#ifndef SWIG -/// @brief Error code used by Futures returned by this API. -enum ErrorCode { - kErrorCodeSuccess = 0, - kErrorCodeFailed, -}; -#endif // SWIG - -/// @brief Enum describing the strength of a dynamic links match. -/// -/// This version is local to dynamic links; there is a similar enum in invites -/// and another internal version in app. -enum LinkMatchStrength { - /// No match has been achieved - kLinkMatchStrengthNoMatch = 0, - - /// The match between the Dynamic Link and device is not perfect. You should - /// not reveal any personal information related to the Dynamic Link. - kLinkMatchStrengthWeakMatch, - - /// The match between the Dynamic Link and this device has a high confidence, - /// but there is a small possibility of error. - kLinkMatchStrengthStrongMatch, - - /// The match between the Dynamic Link and the device is exact. You may - /// safely reveal any personal information related to this Dynamic Link. - kLinkMatchStrengthPerfectMatch -}; - -/// @brief The received Dynamic Link. -struct DynamicLink { - /// The URL that was passed to the app. - std::string url; - /// The match strength of the dynamic link. - LinkMatchStrength match_strength; -}; - -/// @brief Base class used to receive Dynamic Links. -class Listener { - public: - virtual ~Listener(); - - /// Called on the client when a dynamic link arrives. - /// - /// @param[in] dynamic_link The data describing the Dynamic Link. - virtual void OnDynamicLinkReceived(const DynamicLink* dynamic_link) = 0; -}; - -/// @brief Initialize Firebase Dynamic Links. -/// -/// After Initialize is called, the implementation may call functions on the -/// Listener provided at any time. -/// -/// @param[in] app The Firebase App object for this application. -/// @param[in] listener A Listener object that receives Dynamic Links. -/// -/// @return kInitResultSuccess if initialization succeeded, or -/// kInitResultFailedMissingDependency on Android if Google Play services is -/// not available on the current device. -/// -/// @deprecated Dynamic Links is now deprecated. Please see the support -/// documentation at https://firebase.google.com/support/dynamic-links-faq -/// for more information. -FIREBASE_DEPRECATED InitResult Initialize(const App& app, Listener* listener); - -/// @brief Terminate Firebase Dynamic Links. -/// -/// @deprecated Dynamic Links is now deprecated. Please see the support -/// documentation at https://firebase.google.com/support/dynamic-links-faq -/// for more information. -FIREBASE_DEPRECATED void Terminate(); - -/// @brief Set the listener for receiving Dynamic Links. -/// -/// @param[in] listener A Listener object that receives Dynamic Links. -/// -/// @return Pointer to the previously set listener. -/// -/// @deprecated Dynamic Links is now deprecated. Please see the support -/// documentation at https://firebase.google.com/support/dynamic-links-faq -/// for more information. -FIREBASE_DEPRECATED Listener* SetListener(Listener* listener); - -/// Fetch any pending dynamic links. Each pending link will trigger a call to -/// the registered Listener class. -/// -/// This function is implicitly called on initialization. On iOS this is called -/// automatically when the app gains focus, but on Android this needs to be -/// called manually. -/// -/// @deprecated Dynamic Links is now deprecated. Please see the support -/// documentation at https://firebase.google.com/support/dynamic-links-faq -/// for more information. -FIREBASE_DEPRECATED void Fetch(); - -} // namespace dynamic_links -} // namespace firebase - -#endif // FIREBASE_DYNAMIC_LINKS_SRC_INCLUDE_FIREBASE_DYNAMIC_LINKS_H_ diff --git a/dynamic_links/src/include/firebase/dynamic_links/components.h b/dynamic_links/src/include/firebase/dynamic_links/components.h deleted file mode 100644 index 7a8e8fa1a4..0000000000 --- a/dynamic_links/src/include/firebase/dynamic_links/components.h +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef FIREBASE_DYNAMIC_LINKS_SRC_INCLUDE_FIREBASE_DYNAMIC_LINKS_COMPONENTS_H_ -#define FIREBASE_DYNAMIC_LINKS_SRC_INCLUDE_FIREBASE_DYNAMIC_LINKS_COMPONENTS_H_ - -#include -#include -#include - -#include "firebase/future.h" - -namespace firebase { - -namespace dynamic_links { - -/// @brief Google Analytics Parameters. -/// -/// Note that the strings used by the struct are not copied, as so must -/// either be statically allocated, or must persist in memory until the -/// DynamicLinkComponents that uses them goes out of scope. -struct GoogleAnalyticsParameters { - /// Constructs an empty set of Google Analytics parameters. - GoogleAnalyticsParameters() - : source(nullptr), - medium(nullptr), - campaign(nullptr), - term(nullptr), - content(nullptr) {} - - /// The campaign source; used to identify a search engine, newsletter, - /// or other source. - const char* source; - /// The campaign medium; used to identify a medium such as email or - /// cost-per-click (cpc). - const char* medium; - /// The campaign name; The individual campaign name, slogan, promo code, etc. - /// for a product. - const char* campaign; - /// The campaign term; used with paid search to supply the keywords for ads. - const char* term; - /// The campaign content; used for A/B testing and content-targeted ads to - /// differentiate ads or links that point to the same URL. - const char* content; -}; - -/// @brief iOS Parameters. -/// -/// Note that the strings used by the struct are not copied, as so must -/// either be statically allocated, or must persist in memory until the -/// DynamicLinkComponents that uses them goes out of scope. -struct IOSParameters { - /// Constructs a set of IOS parameters with the given bundle id. - /// - /// @param bundle_id_ The parameters ID of the iOS app to use to open the - /// link. - IOSParameters(const char* bundle_id_) - : bundle_id(bundle_id_), - fallback_url(nullptr), - custom_scheme(nullptr), - ipad_fallback_url(nullptr), - ipad_bundle_id(nullptr), - app_store_id(nullptr), - minimum_version(nullptr) {} - - /// Constructs an empty set of IOS parameters. - IOSParameters() - : bundle_id(nullptr), - fallback_url(nullptr), - custom_scheme(nullptr), - ipad_fallback_url(nullptr), - ipad_bundle_id(nullptr), - app_store_id(nullptr), - minimum_version(nullptr) {} - - /// The parameters ID of the iOS app to use to open the link. The app must be - /// connected to your project from the Overview page of the Firebase console. - /// Note this field is required. - const char* bundle_id; - /// The link to open on iOS if the app is not installed. - /// - /// Specify this to do something other than install your app from the - /// App Store when the app isn't installed, such as open the mobile - /// web version of the content, or display a promotional page for your app. - const char* fallback_url; - /// The app's custom URL scheme, if defined to be something other than your - /// app's parameters ID. - const char* custom_scheme; - /// The link to open on iPad if the app is not installed. - /// - /// Overrides fallback_url when on iPad. - const char* ipad_fallback_url; - /// The iPad parameters ID of the app. - const char* ipad_bundle_id; - /// The App Store ID, used to send users to the App Store when the app isn't - /// installed. - const char* app_store_id; - /// The minimum version of your app that can open the link. - const char* minimum_version; -}; - -/// @brief iTunes Connect App Analytics Parameters. -/// -/// Note that the strings used by the struct are not copied, as so must -/// either be statically allocated, or must persist in memory until the -/// DynamicLinkComponents that uses them goes out of scope. -struct ITunesConnectAnalyticsParameters { - /// Constructs an empty set of ITunes Connect Analytics parameters. - ITunesConnectAnalyticsParameters() - : provider_token(nullptr), - affiliate_token(nullptr), - campaign_token(nullptr) {} - - /// The provider token that enables analytics for Dynamic Links from - /// within iTunes Connect. - const char* provider_token; - /// The affiliate token used to create affiliate-coded links. - const char* affiliate_token; - /// The campaign token that developers can add to any link in order to - /// track sales from a specific marketing campaign. - const char* campaign_token; -}; - -/// @brief Android Parameters. -/// -/// Note that the strings used by the struct are not copied, as so must -/// either be statically allocated, or must persist in memory until the -/// DynamicLinkComponents that uses them goes out of scope. -struct AndroidParameters { - /// Constructs a set of Android parameters with the given package name. - /// - /// The package name of the Android app to use to open the link. - AndroidParameters(const char* package_name_) - : package_name(package_name_), - fallback_url(nullptr), - minimum_version(0) {} - - /// Constructs an empty set of Android parameters. - AndroidParameters() - : package_name(nullptr), fallback_url(nullptr), minimum_version(0) {} - - /// The package name of the Android app to use to open the link. The app - /// must be connected to your project from the Overview page of the Firebase - /// console. - /// Note this field is required. - const char* package_name; - /// The link to open when the app isn't installed. - /// - /// Specify this to do something other than install your app from the - /// Play Store when the app isn't installed, such as open the mobile web - /// version of the content, or display a promotional page for your app. - const char* fallback_url; - /// The versionCode of the minimum version of your app that can open the link. - int minimum_version; -}; - -/// @brief Social meta-tag Parameters. -/// -/// Note that the strings used by the struct are not copied, as so must -/// either be statically allocated, or must persist in memory until the -/// DynamicLinkComponents that uses them goes out of scope. -struct SocialMetaTagParameters { - /// Constructs an empty set of Social meta-tag parameters. - SocialMetaTagParameters() - : title(nullptr), description(nullptr), image_url(nullptr) {} - - /// The title to use when the Dynamic Link is shared in a social post. - const char* title; - /// The description to use when the Dynamic Link is shared in a social post. - const char* description; - /// The URL to an image related to this link. - const char* image_url; -}; - -/// @brief The desired path length for shortened Dynamic Link URLs. -enum PathLength { - /// Uses the server-default for the path length. - /// See https://goo.gl/8yDAqC for more information. - kPathLengthDefault = 0, - /// Typical short link for non-sensitive links. - kPathLengthShort, - /// Short link that uses a very long path to make it more difficult to - /// guess. Useful for sensitive links. - kPathLengthUnguessable, -}; - -/// @brief Additional options for Dynamic Link creation. -struct DynamicLinkOptions { - /// Constructs an empty set of Dynamic Link options. - DynamicLinkOptions() : path_length(kPathLengthDefault) {} - - /// The desired path length for shortened Dynamic Link URLs. - PathLength path_length; -}; - -/// @brief The returned value from creating a Dynamic Link. -struct GeneratedDynamicLink { - /// The Dynamic Link value. - std::string url; - /// Information about potential warnings on link creation. - /// - /// Usually presence of warnings means parameter format errors, parameter - /// value errors, or missing parameters. - std::vector warnings; - /// If non-empty, the cause of the Dynamic Link generation failure. - std::string error; -}; - -/// @brief The information needed to generate a Dynamic Link. -/// -/// Note that the strings used by the struct are not copied, as so must -/// either be statically allocated, or must persist in memory until this -/// struct goes out of scope. -struct DynamicLinkComponents { - /// The link your app will open. - /// You can specify any URL your app can handle, such as a link to your - /// app's content, or a URL that initiates some - /// app-specific logic such as crediting the user with a coupon, or - /// displaying a specific welcome screen. This link must be a well-formatted - /// URL, be properly URL-encoded, and use the HTTP or HTTPS scheme. - /// Note, this field is required. - const char* link; - /// The domain (of the form "https://xyz.app.goo.gl") to use for this Dynamic - /// Link. You can find this value in the Dynamic Links section of the Firebase - /// console. - /// - /// If you have set up custom domains on your project, set this to your - /// project's custom domain as listed in the Firebase console. - /// - /// Only https:// links are supported. - /// - /// Note, this field is required. - const char* domain_uri_prefix; - /// The Google Analytics parameters. - GoogleAnalyticsParameters* google_analytics_parameters; - /// The iOS parameters. - IOSParameters* ios_parameters; - /// The iTunes Connect App Analytics parameters. - ITunesConnectAnalyticsParameters* itunes_connect_analytics_parameters; - /// The Android parameters. - AndroidParameters* android_parameters; - /// The social meta-tag parameters. - SocialMetaTagParameters* social_meta_tag_parameters; - - /// Default constructor, initializes all fields to null. - DynamicLinkComponents() - : link(nullptr), - domain_uri_prefix(nullptr), - google_analytics_parameters(nullptr), - ios_parameters(nullptr), - itunes_connect_analytics_parameters(nullptr), - android_parameters(nullptr), - social_meta_tag_parameters(nullptr) {} - - /// Constructor that initializes with the given link and domain. - /// - /// @param link_ The link your app will open. - /// @param domain_uri_prefix_ The domain (of the form - /// "https://xyz.app.goo.gl") to use for this Dynamic Link. You can find this - /// value in the Dynamic Links section of the Firebase console. If you have - /// set up custom domains on your project, set this to your project's custom - /// domain as listed in the Firebase console. Note: If you do not specify - /// "https://" as the URI scheme, it will be added. - DynamicLinkComponents(const char* link_, const char* domain_uri_prefix_) - : link(link_), - domain_uri_prefix(domain_uri_prefix_), - google_analytics_parameters(nullptr), - ios_parameters(nullptr), - itunes_connect_analytics_parameters(nullptr), - android_parameters(nullptr), - social_meta_tag_parameters(nullptr) { - // For backwards compatibility with dynamic_link_domain, if - // domain_uri_prefix doesn't start with "https://", add it. - static const char kHttpsPrefix[] = "https://"; - static const size_t kHttpsPrefixLength = sizeof(kHttpsPrefix) - 1; - if (strncmp(domain_uri_prefix, kHttpsPrefix, kHttpsPrefixLength) != 0) { - domain_uri_prefix_with_scheme = - std::string(kHttpsPrefix) + domain_uri_prefix; - domain_uri_prefix = domain_uri_prefix_with_scheme.c_str(); - } - } - -#ifndef INTERNAL_EXPERIMENTAL - - private: -#endif // INTERNAL_EXPERIMENTAL - std::string domain_uri_prefix_with_scheme; -}; - -/// Creates a long Dynamic Link from the given parameters. -GeneratedDynamicLink GetLongLink(const DynamicLinkComponents& components); - -/// Creates a shortened Dynamic Link from the given parameters. -/// @param components: Settings used to configure the behavior for the link. -Future GetShortLink( - const DynamicLinkComponents& components); - -/// Creates a shortened Dynamic Link from the given parameters. -/// @param components: Settings used to configure the behavior for the link. -/// @param options: Additional options for Dynamic Link shortening, indicating -/// whether or not to produce an unguessable or shortest possible link. -/// No references to the options object will be retained after the call. -Future GetShortLink( - const DynamicLinkComponents& components, const DynamicLinkOptions& options); - -/// Creates a shortened Dynamic Link from a given long Dynamic Link. -/// @param long_dynamic_link A link previously generated from GetLongLink. -Future GetShortLink(const char* long_dynamic_link); - -/// Creates a shortened Dynamic Link from a given long Dynamic Link. -/// @param long_dynamic_link: A link previously generated from GetLongLink. -/// @param options: Additional options for Dynamic Link shortening, indicating -/// whether or not to produce an unguessable or shortest possible link. -/// No references to the options object will be retained after the call. -Future GetShortLink(const char* long_dynamic_link, - const DynamicLinkOptions& options); - -/// Get the (possibly still pending) results of the most recent GetShortUrl -/// call. -Future GetShortLinkLastResult(); - -} // namespace dynamic_links -} // namespace firebase - -#endif // FIREBASE_DYNAMIC_LINKS_SRC_INCLUDE_FIREBASE_DYNAMIC_LINKS_COMPONENTS_H_ diff --git a/dynamic_links/src/listener.cc b/dynamic_links/src/listener.cc deleted file mode 100644 index d342673dd9..0000000000 --- a/dynamic_links/src/listener.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "dynamic_links/src/include/firebase/dynamic_links.h" - -namespace firebase { -namespace dynamic_links { - -// Non-inline implementation of Listener's virtual destructor -// to prevent its vtable being emitted in each translation unit. -Listener::~Listener() {} - -} // namespace dynamic_links -} // namespace firebase diff --git a/release_build_files/Android/firebase_dependencies.gradle b/release_build_files/Android/firebase_dependencies.gradle index 142de79cc7..efcc1983b6 100644 --- a/release_build_files/Android/firebase_dependencies.gradle +++ b/release_build_files/Android/firebase_dependencies.gradle @@ -24,7 +24,6 @@ def firebaseDependenciesMap = [ 'analytics' : ['com.google.firebase:firebase-analytics'], 'auth' : ['com.google.firebase:firebase-auth'], 'database' : ['com.google.firebase:firebase-database'], - 'dynamic_links' : ['com.google.firebase:firebase-dynamic-links'], 'firestore' : ['com.google.firebase:firebase-firestore'], 'functions' : ['com.google.firebase:firebase-functions'], 'gma' : ['com.google.android.gms:play-services-ads:23.0.0', @@ -66,9 +65,6 @@ class Dependencies { def getDatabase() { libSet.add('database') } - def getDynamicLinks() { - libSet.add('dynamic_links') - } def getFirestore() { libSet.add('firestore') } @@ -81,9 +77,6 @@ class Dependencies { def getInstallations() { libSet.add('installations') } - def getInvites() { - libSet.add('invites') - } def getMessaging() { libSet.add('messaging') } diff --git a/release_build_files/CMakeLists.txt b/release_build_files/CMakeLists.txt index 594440937d..f25a66bcad 100644 --- a/release_build_files/CMakeLists.txt +++ b/release_build_files/CMakeLists.txt @@ -93,7 +93,6 @@ add_firebase_target(firebase_analytics) add_firebase_target(firebase_app_check) add_firebase_target(firebase_auth) add_firebase_target(firebase_database) -add_firebase_target(firebase_dynamic_links) add_firebase_target(firebase_firestore) add_firebase_target(firebase_functions) add_firebase_target(firebase_gma) diff --git a/settings.gradle b/settings.gradle index ad2d909d3d..2877286a44 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,6 @@ rootProject.name = 'firebase_cpp_sdk' include ':app', ':app:app_resources', ':app:google_api_resources', - ':app:invites_resources', ':app_check', ":app_check:app_check_resources", ':analytics', @@ -10,7 +9,6 @@ include ':app', ':auth:auth_resources', ':database', ':database:database_resources', - ':dynamic_links', ':firestore', ':firestore:firestore_resources', ':functions',