From 0d1988b5a025de85b7f9839eddf49c2ddcb39689 Mon Sep 17 00:00:00 2001 From: John Borges Date: Mon, 29 Mar 2021 09:29:09 -0400 Subject: [PATCH 01/27] chore(appcenter-crashes): add new plugin --- appcenter-crashes/.eslintignore | 2 + appcenter-crashes/.gitignore | 61 ++ appcenter-crashes/.prettierignore | 2 + appcenter-crashes/CONTRIBUTING.md | 52 ++ ...CapacitorCommunityAppcenterCrashes.podspec | 19 + appcenter-crashes/README.md | 37 ++ appcenter-crashes/android/.gitignore | 1 + appcenter-crashes/android/build.gradle | 58 ++ appcenter-crashes/android/gradle.properties | 24 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 58910 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + appcenter-crashes/android/gradlew | 185 ++++++ appcenter-crashes/android/gradlew.bat | 104 ++++ appcenter-crashes/android/proguard-rules.pro | 21 + appcenter-crashes/android/settings.gradle | 2 + .../android/ExampleInstrumentedTest.java | 26 + .../android/src/main/AndroidManifest.xml | 3 + .../plugins/example/AppCenterCrashes.java | 8 + .../example/AppCenterCrashesPlugin.java | 22 + .../android/src/main/res/.gitkeep | 0 .../com/getcapacitor/ExampleUnitTest.java | 18 + .../ios/Plugin.xcodeproj/project.pbxproj | 569 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/Plugin.xcscheme | 77 +++ .../xcschemes/PluginTests.xcscheme | 68 +++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../ios/Plugin/AppCenterCrashes.swift | 7 + .../ios/Plugin/AppCenterCrashesPlugin.h | 10 + .../ios/Plugin/AppCenterCrashesPlugin.m | 8 + .../ios/Plugin/AppCenterCrashesPlugin.swift | 18 + appcenter-crashes/ios/Plugin/Info.plist | 24 + .../AppCenterCrashesPluginTests.swift | 25 + appcenter-crashes/ios/PluginTests/Info.plist | 22 + appcenter-crashes/ios/Podfile | 17 + appcenter-crashes/package.json | 78 +++ appcenter-crashes/rollup.config.js | 22 + appcenter-crashes/src/definitions.ts | 3 + appcenter-crashes/src/index.ts | 13 + appcenter-crashes/src/web.ts | 12 + appcenter-crashes/tsconfig.json | 19 + lerna.json | 1 + 43 files changed, 1676 insertions(+) create mode 100644 appcenter-crashes/.eslintignore create mode 100644 appcenter-crashes/.gitignore create mode 100644 appcenter-crashes/.prettierignore create mode 100644 appcenter-crashes/CONTRIBUTING.md create mode 100644 appcenter-crashes/CapacitorCommunityAppcenterCrashes.podspec create mode 100644 appcenter-crashes/README.md create mode 100644 appcenter-crashes/android/.gitignore create mode 100644 appcenter-crashes/android/build.gradle create mode 100644 appcenter-crashes/android/gradle.properties create mode 100644 appcenter-crashes/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 appcenter-crashes/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 appcenter-crashes/android/gradlew create mode 100644 appcenter-crashes/android/gradlew.bat create mode 100644 appcenter-crashes/android/proguard-rules.pro create mode 100644 appcenter-crashes/android/settings.gradle create mode 100644 appcenter-crashes/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java create mode 100644 appcenter-crashes/android/src/main/AndroidManifest.xml create mode 100644 appcenter-crashes/android/src/main/java/com/mycompany/plugins/example/AppCenterCrashes.java create mode 100644 appcenter-crashes/android/src/main/java/com/mycompany/plugins/example/AppCenterCrashesPlugin.java create mode 100644 appcenter-crashes/android/src/main/res/.gitkeep create mode 100644 appcenter-crashes/android/src/test/java/com/getcapacitor/ExampleUnitTest.java create mode 100644 appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj create mode 100644 appcenter-crashes/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 appcenter-crashes/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 appcenter-crashes/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme create mode 100644 appcenter-crashes/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme create mode 100644 appcenter-crashes/ios/Plugin.xcworkspace/contents.xcworkspacedata create mode 100644 appcenter-crashes/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 appcenter-crashes/ios/Plugin/AppCenterCrashes.swift create mode 100644 appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.h create mode 100644 appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m create mode 100644 appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift create mode 100644 appcenter-crashes/ios/Plugin/Info.plist create mode 100644 appcenter-crashes/ios/PluginTests/AppCenterCrashesPluginTests.swift create mode 100644 appcenter-crashes/ios/PluginTests/Info.plist create mode 100644 appcenter-crashes/ios/Podfile create mode 100644 appcenter-crashes/package.json create mode 100644 appcenter-crashes/rollup.config.js create mode 100644 appcenter-crashes/src/definitions.ts create mode 100644 appcenter-crashes/src/index.ts create mode 100644 appcenter-crashes/src/web.ts create mode 100644 appcenter-crashes/tsconfig.json diff --git a/appcenter-crashes/.eslintignore b/appcenter-crashes/.eslintignore new file mode 100644 index 0000000..9d0b71a --- /dev/null +++ b/appcenter-crashes/.eslintignore @@ -0,0 +1,2 @@ +build +dist diff --git a/appcenter-crashes/.gitignore b/appcenter-crashes/.gitignore new file mode 100644 index 0000000..70ccbf7 --- /dev/null +++ b/appcenter-crashes/.gitignore @@ -0,0 +1,61 @@ +# node files +dist +node_modules + +# iOS files +Pods +Podfile.lock +Build +xcuserdata + +# macOS files +.DS_Store + + + +# Based on Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore + +# Built application files +*.apk +*.ap_ + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin +gen +out + +# Gradle files +.gradle +build + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation + +# Android Studio captures folder +captures + +# IntelliJ +*.iml +.idea + +# Keystore files +# Uncomment the following line if you do not want to check your keystore files in. +#*.jks + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild diff --git a/appcenter-crashes/.prettierignore b/appcenter-crashes/.prettierignore new file mode 100644 index 0000000..9d0b71a --- /dev/null +++ b/appcenter-crashes/.prettierignore @@ -0,0 +1,2 @@ +build +dist diff --git a/appcenter-crashes/CONTRIBUTING.md b/appcenter-crashes/CONTRIBUTING.md new file mode 100644 index 0000000..3f87518 --- /dev/null +++ b/appcenter-crashes/CONTRIBUTING.md @@ -0,0 +1,52 @@ +# Contributing + +This guide provides instructions for contributing to this Capacitor plugin. + +## Developing + +### Local Setup + +1. Fork and clone the repo. +1. Install the dependencies. + + ```shell + npm install + ``` + +1. Install SwiftLint if you're on macOS. + + ```shell + brew install swiftlint + ``` + +### Scripts + +#### `npm run build` + +Build the plugin web assets and generate plugin API documentation using [`@capacitor/docgen`](https://github.com/ionic-team/capacitor-docgen). + +It will compile the TypeScript code from `src/` into ESM JavaScript in `dist/esm/`. These files are used in apps with bundlers when your plugin is imported. + +Then, Rollup will bundle the code into a single file at `dist/plugin.js`. This file is used in apps without bundlers by including it as a script in `index.html`. + +#### `npm run verify` + +Build and validate the web and native projects. + +This is useful to run in CI to verify that the plugin builds for all platforms. + +#### `npm run lint` / `npm run fmt` + +Check formatting and code quality, autoformat/autofix if possible. + +This template is integrated with ESLint, Prettier, and SwiftLint. Using these tools is completely optional, but the [Capacitor Community](https://github.com/capacitor-community/) strives to have consistent code style and structure for easier cooperation. + +## Publishing + +There is a `prepublishOnly` hook in `package.json` which prepares the plugin before publishing, so all you need to do is run: + +```shell +npm publish +``` + +> **Note**: The [`files`](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#files) array in `package.json` specifies which files get published. If you rename files/directories or add files elsewhere, you may need to update it. diff --git a/appcenter-crashes/CapacitorCommunityAppcenterCrashes.podspec b/appcenter-crashes/CapacitorCommunityAppcenterCrashes.podspec new file mode 100644 index 0000000..7e3f821 --- /dev/null +++ b/appcenter-crashes/CapacitorCommunityAppcenterCrashes.podspec @@ -0,0 +1,19 @@ +require 'json' + +package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) + +Pod::Spec.new do |s| + s.name = 'CapacitorCommunityAppcenterCrashes' + s.version = package['version'] + s.summary = package['description'] + s.license = package['license'] + s.homepage = package['repository']['url'] + s.author = package['author'] + s.source = { :git => package['repository']['url'], :tag => s.version.to_s } + s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' + s.ios.deployment_target = '12.0' + s.dependency 'Capacitor' + s.dependency 'AppCenter/Crashes' + s.static_framework = true + s.swift_version = '5.1' +end diff --git a/appcenter-crashes/README.md b/appcenter-crashes/README.md new file mode 100644 index 0000000..fbcbc59 --- /dev/null +++ b/appcenter-crashes/README.md @@ -0,0 +1,37 @@ +# @capacitor-community/appcenter-crashes + +App Center Crashes records the state of the app and device and automatically generates a crash log. + +## Install + +```bash +npm install @capacitor-community/appcenter-crashes +npx cap sync +``` + +## API + + + +* [`echo(...)`](#echo) + + + + + + +### echo(...) + +```typescript +echo(options: { value: string; }) => any +``` + +| Param | Type | +| ------------- | ------------------------------- | +| **`options`** | { value: string; } | + +**Returns:** any + +-------------------- + + diff --git a/appcenter-crashes/android/.gitignore b/appcenter-crashes/android/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/appcenter-crashes/android/.gitignore @@ -0,0 +1 @@ +/build diff --git a/appcenter-crashes/android/build.gradle b/appcenter-crashes/android/build.gradle new file mode 100644 index 0000000..f0f8827 --- /dev/null +++ b/appcenter-crashes/android/build.gradle @@ -0,0 +1,58 @@ +ext { + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.12' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.1.0' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.1' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.2.0' +} + +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:4.1.1' + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30 + defaultConfig { + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + lintOptions { + abortOnError false + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +repositories { + google() + jcenter() + mavenCentral() +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':capacitor-android') + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" +} diff --git a/appcenter-crashes/android/gradle.properties b/appcenter-crashes/android/gradle.properties new file mode 100644 index 0000000..0566c22 --- /dev/null +++ b/appcenter-crashes/android/gradle.properties @@ -0,0 +1,24 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true diff --git a/appcenter-crashes/android/gradle/wrapper/gradle-wrapper.jar b/appcenter-crashes/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..62d4c053550b91381bbd28b1afc82d634bf73a8a GIT binary patch literal 58910 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 literal 0 HcmV?d00001 diff --git a/appcenter-crashes/android/gradle/wrapper/gradle-wrapper.properties b/appcenter-crashes/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..186b715 --- /dev/null +++ b/appcenter-crashes/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/appcenter-crashes/android/gradlew b/appcenter-crashes/android/gradlew new file mode 100755 index 0000000..fbd7c51 --- /dev/null +++ b/appcenter-crashes/android/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# 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 +# +# https://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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +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" -a "$nonstop" = "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 or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # 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=`expr $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 + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/appcenter-crashes/android/gradlew.bat b/appcenter-crashes/android/gradlew.bat new file mode 100644 index 0000000..5093609 --- /dev/null +++ b/appcenter-crashes/android/gradlew.bat @@ -0,0 +1,104 @@ +@rem +@rem Copyright 2015 the original author or authors. +@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 https://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. +@rem + +@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 + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@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="-Xmx64m" "-Xms64m" + +@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 Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_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=%* + +: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/appcenter-crashes/android/proguard-rules.pro b/appcenter-crashes/android/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/appcenter-crashes/android/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/appcenter-crashes/android/settings.gradle b/appcenter-crashes/android/settings.gradle new file mode 100644 index 0000000..1e5b843 --- /dev/null +++ b/appcenter-crashes/android/settings.gradle @@ -0,0 +1,2 @@ +include ':capacitor-android' +project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') \ No newline at end of file diff --git a/appcenter-crashes/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java b/appcenter-crashes/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java new file mode 100644 index 0000000..58020e1 --- /dev/null +++ b/appcenter-crashes/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.getcapacitor.android; + +import static org.junit.Assert.*; + +import android.content.Context; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.getcapacitor.android", appContext.getPackageName()); + } +} diff --git a/appcenter-crashes/android/src/main/AndroidManifest.xml b/appcenter-crashes/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b8df3c2 --- /dev/null +++ b/appcenter-crashes/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/appcenter-crashes/android/src/main/java/com/mycompany/plugins/example/AppCenterCrashes.java b/appcenter-crashes/android/src/main/java/com/mycompany/plugins/example/AppCenterCrashes.java new file mode 100644 index 0000000..1202770 --- /dev/null +++ b/appcenter-crashes/android/src/main/java/com/mycompany/plugins/example/AppCenterCrashes.java @@ -0,0 +1,8 @@ +package com.mycompany.plugins.example; + +public class AppCenterCrashes { + + public String echo(String value) { + return value; + } +} diff --git a/appcenter-crashes/android/src/main/java/com/mycompany/plugins/example/AppCenterCrashesPlugin.java b/appcenter-crashes/android/src/main/java/com/mycompany/plugins/example/AppCenterCrashesPlugin.java new file mode 100644 index 0000000..7e769a8 --- /dev/null +++ b/appcenter-crashes/android/src/main/java/com/mycompany/plugins/example/AppCenterCrashesPlugin.java @@ -0,0 +1,22 @@ +package com.mycompany.plugins.example; + +import com.getcapacitor.JSObject; +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginMethod; +import com.getcapacitor.annotation.CapacitorPlugin; + +@CapacitorPlugin(name = "AppCenterCrashes") +public class AppCenterCrashesPlugin extends Plugin { + + private AppCenterCrashes implementation = new AppCenterCrashes(); + + @PluginMethod + public void echo(PluginCall call) { + String value = call.getString("value"); + + JSObject ret = new JSObject(); + ret.put("value", implementation.echo(value)); + call.resolve(ret); + } +} diff --git a/appcenter-crashes/android/src/main/res/.gitkeep b/appcenter-crashes/android/src/main/res/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/appcenter-crashes/android/src/test/java/com/getcapacitor/ExampleUnitTest.java b/appcenter-crashes/android/src/test/java/com/getcapacitor/ExampleUnitTest.java new file mode 100644 index 0000000..a0fed0c --- /dev/null +++ b/appcenter-crashes/android/src/test/java/com/getcapacitor/ExampleUnitTest.java @@ -0,0 +1,18 @@ +package com.getcapacitor; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} diff --git a/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj b/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj new file mode 100644 index 0000000..cfd29d4 --- /dev/null +++ b/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj @@ -0,0 +1,569 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */; }; + 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */; }; + 2F98D68224C9AAE500613A4C /* AppCenterCrashes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F98D68124C9AAE400613A4C /* AppCenterCrashes.swift */; }; + 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFF88201F53D600D50D53 /* Plugin.framework */; }; + 50ADFF97201F53D600D50D53 /* AppCenterCrashesPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFF96201F53D600D50D53 /* AppCenterCrashesPluginTests.swift */; }; + 50ADFF99201F53D600D50D53 /* AppCenterCrashesPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 50ADFF8B201F53D600D50D53 /* AppCenterCrashesPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFFA52020D75100D50D53 /* Capacitor.framework */; }; + 50ADFFA82020EE4F00D50D53 /* AppCenterCrashesPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* AppCenterCrashesPlugin.m */; }; + 50E1A94820377CB70090CE1A /* AppCenterCrashesPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* AppCenterCrashesPlugin.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 50ADFF93201F53D600D50D53 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 50ADFF7F201F53D600D50D53 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 50ADFF87201F53D600D50D53; + remoteInfo = Plugin; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 2F98D68124C9AAE400613A4C /* AppCenterCrashes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCenterCrashes.swift; sourceTree = ""; }; + 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50ADFF88201F53D600D50D53 /* Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50ADFF8B201F53D600D50D53 /* AppCenterCrashesPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppCenterCrashesPlugin.h; sourceTree = ""; }; + 50ADFF8C201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 50ADFF91201F53D600D50D53 /* PluginTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PluginTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 50ADFF96201F53D600D50D53 /* AppCenterCrashesPluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCenterCrashesPluginTests.swift; sourceTree = ""; }; + 50ADFF98201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 50ADFFA52020D75100D50D53 /* Capacitor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Capacitor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50ADFFA72020EE4F00D50D53 /* AppCenterCrashesPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppCenterCrashesPlugin.m; sourceTree = ""; }; + 50E1A94720377CB70090CE1A /* AppCenterCrashesPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCenterCrashesPlugin.swift; sourceTree = ""; }; + 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = ""; }; + 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = ""; }; + 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; + F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = ""; }; + F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 50ADFF84201F53D600D50D53 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */, + 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50ADFF8E201F53D600D50D53 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */, + 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 50ADFF7E201F53D600D50D53 = { + isa = PBXGroup; + children = ( + 50ADFF8A201F53D600D50D53 /* Plugin */, + 50ADFF95201F53D600D50D53 /* PluginTests */, + 50ADFF89201F53D600D50D53 /* Products */, + 8C8E7744173064A9F6D438E3 /* Pods */, + A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */, + ); + sourceTree = ""; + }; + 50ADFF89201F53D600D50D53 /* Products */ = { + isa = PBXGroup; + children = ( + 50ADFF88201F53D600D50D53 /* Plugin.framework */, + 50ADFF91201F53D600D50D53 /* PluginTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 50ADFF8A201F53D600D50D53 /* Plugin */ = { + isa = PBXGroup; + children = ( + 50E1A94720377CB70090CE1A /* AppCenterCrashesPlugin.swift */, + 2F98D68124C9AAE400613A4C /* AppCenterCrashes.swift */, + 50ADFF8B201F53D600D50D53 /* AppCenterCrashesPlugin.h */, + 50ADFFA72020EE4F00D50D53 /* AppCenterCrashesPlugin.m */, + 50ADFF8C201F53D600D50D53 /* Info.plist */, + ); + path = Plugin; + sourceTree = ""; + }; + 50ADFF95201F53D600D50D53 /* PluginTests */ = { + isa = PBXGroup; + children = ( + 50ADFF96201F53D600D50D53 /* AppCenterCrashesPluginTests.swift */, + 50ADFF98201F53D600D50D53 /* Info.plist */, + ); + path = PluginTests; + sourceTree = ""; + }; + 8C8E7744173064A9F6D438E3 /* Pods */ = { + isa = PBXGroup; + children = ( + 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */, + 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */, + 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */, + F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 50ADFFA52020D75100D50D53 /* Capacitor.framework */, + 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */, + F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 50ADFF85201F53D600D50D53 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFF99201F53D600D50D53 /* AppCenterCrashesPlugin.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 50ADFF87201F53D600D50D53 /* Plugin */ = { + isa = PBXNativeTarget; + buildConfigurationList = 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */; + buildPhases = ( + AB5B3E54B4E897F32C2279DA /* [CP] Check Pods Manifest.lock */, + 50ADFF83201F53D600D50D53 /* Sources */, + 50ADFF84201F53D600D50D53 /* Frameworks */, + 50ADFF85201F53D600D50D53 /* Headers */, + 50ADFF86201F53D600D50D53 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Plugin; + productName = Plugin; + productReference = 50ADFF88201F53D600D50D53 /* Plugin.framework */; + productType = "com.apple.product-type.framework"; + }; + 50ADFF90201F53D600D50D53 /* PluginTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */; + buildPhases = ( + 0596884F929ED6F1DE134961 /* [CP] Check Pods Manifest.lock */, + 50ADFF8D201F53D600D50D53 /* Sources */, + 50ADFF8E201F53D600D50D53 /* Frameworks */, + 50ADFF8F201F53D600D50D53 /* Resources */, + 8E97F58B69A94C6503FC9C85 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 50ADFF94201F53D600D50D53 /* PBXTargetDependency */, + ); + name = PluginTests; + productName = PluginTests; + productReference = 50ADFF91201F53D600D50D53 /* PluginTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 50ADFF7F201F53D600D50D53 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1160; + ORGANIZATIONNAME = "Max Lynch"; + TargetAttributes = { + 50ADFF87201F53D600D50D53 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + }; + 50ADFF90201F53D600D50D53 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 50ADFF82201F53D600D50D53 /* Build configuration list for PBXProject "Plugin" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 50ADFF7E201F53D600D50D53; + productRefGroup = 50ADFF89201F53D600D50D53 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 50ADFF87201F53D600D50D53 /* Plugin */, + 50ADFF90201F53D600D50D53 /* PluginTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 50ADFF86201F53D600D50D53 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50ADFF8F201F53D600D50D53 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 0596884F929ED6F1DE134961 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-PluginTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 8E97F58B69A94C6503FC9C85 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Capacitor/Capacitor.framework", + "${BUILT_PRODUCTS_DIR}/CapacitorCordova/Cordova.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Capacitor.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cordova.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + AB5B3E54B4E897F32C2279DA /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Plugin-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 50ADFF83201F53D600D50D53 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 50E1A94820377CB70090CE1A /* AppCenterCrashesPlugin.swift in Sources */, + 2F98D68224C9AAE500613A4C /* AppCenterCrashes.swift in Sources */, + 50ADFFA82020EE4F00D50D53 /* AppCenterCrashesPlugin.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50ADFF8D201F53D600D50D53 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ADFF97201F53D600D50D53 /* AppCenterCrashesPluginTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 50ADFF94201F53D600D50D53 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 50ADFF87201F53D600D50D53 /* Plugin */; + targetProxy = 50ADFF93201F53D600D50D53 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 50ADFF9A201F53D600D50D53 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "\"${BUILT_PRODUCTS_DIR}/Capacitor\"", + "\"${BUILT_PRODUCTS_DIR}/CapacitorCordova\"", + ); + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + 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 = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 50ADFF9B201F53D600D50D53 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "\"${BUILT_PRODUCTS_DIR}/Capacitor\"", + "\"${BUILT_PRODUCTS_DIR}/CapacitorCordova\"", + ); + GCC_C_LANGUAGE_STANDARD = gnu11; + 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 = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 50ADFF9D201F53D600D50D53 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Plugin/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 50ADFF9E201F53D600D50D53 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Plugin/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 50ADFFA0201F53D600D50D53 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = PluginTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.PluginTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 50ADFFA1201F53D600D50D53 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = PluginTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.PluginTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 50ADFF82201F53D600D50D53 /* Build configuration list for PBXProject "Plugin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50ADFF9A201F53D600D50D53 /* Debug */, + 50ADFF9B201F53D600D50D53 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50ADFF9D201F53D600D50D53 /* Debug */, + 50ADFF9E201F53D600D50D53 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50ADFFA0201F53D600D50D53 /* Debug */, + 50ADFFA1201F53D600D50D53 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 50ADFF7F201F53D600D50D53 /* Project object */; +} diff --git a/appcenter-crashes/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/appcenter-crashes/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/appcenter-crashes/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/appcenter-crashes/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/appcenter-crashes/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/appcenter-crashes/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/appcenter-crashes/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme b/appcenter-crashes/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme new file mode 100644 index 0000000..303f262 --- /dev/null +++ b/appcenter-crashes/ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/appcenter-crashes/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme b/appcenter-crashes/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme new file mode 100644 index 0000000..3d8c88d --- /dev/null +++ b/appcenter-crashes/ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/appcenter-crashes/ios/Plugin.xcworkspace/contents.xcworkspacedata b/appcenter-crashes/ios/Plugin.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..afad624 --- /dev/null +++ b/appcenter-crashes/ios/Plugin.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/appcenter-crashes/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/appcenter-crashes/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/appcenter-crashes/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashes.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashes.swift new file mode 100644 index 0000000..98ff9f8 --- /dev/null +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashes.swift @@ -0,0 +1,7 @@ +import Foundation + +@objc public class AppCenterCrashes: NSObject { + @objc public func echo(_ value: String) -> String { + return value + } +} diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.h b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.h new file mode 100644 index 0000000..f2bd9e0 --- /dev/null +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.h @@ -0,0 +1,10 @@ +#import + +//! Project version number for Plugin. +FOUNDATION_EXPORT double PluginVersionNumber; + +//! Project version string for Plugin. +FOUNDATION_EXPORT const unsigned char PluginVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m new file mode 100644 index 0000000..50e474d --- /dev/null +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m @@ -0,0 +1,8 @@ +#import +#import + +// Define the plugin using the CAP_PLUGIN Macro, and +// each method the plugin supports using the CAP_PLUGIN_METHOD macro. +CAP_PLUGIN(AppCenterCrashesPlugin, "AppCenterCrashes", + CAP_PLUGIN_METHOD(echo, CAPPluginReturnPromise); +) diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift new file mode 100644 index 0000000..86f21de --- /dev/null +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift @@ -0,0 +1,18 @@ +import Foundation +import Capacitor + +/** + * Please read the Capacitor iOS Plugin Development Guide + * here: https://capacitorjs.com/docs/plugins/ios + */ +@objc(AppCenterCrashesPlugin) +public class AppCenterCrashesPlugin: CAPPlugin { + private let implementation = AppCenterCrashes() + + @objc func echo(_ call: CAPPluginCall) { + let value = call.getString("value") ?? "" + call.resolve([ + "value": implementation.echo(value) + ]) + } +} diff --git a/appcenter-crashes/ios/Plugin/Info.plist b/appcenter-crashes/ios/Plugin/Info.plist new file mode 100644 index 0000000..1007fd9 --- /dev/null +++ b/appcenter-crashes/ios/Plugin/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/appcenter-crashes/ios/PluginTests/AppCenterCrashesPluginTests.swift b/appcenter-crashes/ios/PluginTests/AppCenterCrashesPluginTests.swift new file mode 100644 index 0000000..28d7992 --- /dev/null +++ b/appcenter-crashes/ios/PluginTests/AppCenterCrashesPluginTests.swift @@ -0,0 +1,25 @@ +import XCTest +@testable import Plugin + +class AppCenterCrashesTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testEcho() { + // This is an example of a functional test case for a plugin. + // Use XCTAssert and related functions to verify your tests produce the correct results. + + let implementation = AppCenterCrashes() + let value = "Hello, World!" + let result = implementation.echo(value) + + XCTAssertEqual(value, result) + } +} diff --git a/appcenter-crashes/ios/PluginTests/Info.plist b/appcenter-crashes/ios/PluginTests/Info.plist new file mode 100644 index 0000000..6c40a6c --- /dev/null +++ b/appcenter-crashes/ios/PluginTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/appcenter-crashes/ios/Podfile b/appcenter-crashes/ios/Podfile new file mode 100644 index 0000000..71e1eda --- /dev/null +++ b/appcenter-crashes/ios/Podfile @@ -0,0 +1,17 @@ +platform :ios, '12.0' + +def capacitor_pods + # Comment the next line if you're not using Swift and don't want to use dynamic frameworks + use_frameworks! + pod 'Capacitor', :path => '../node_modules/@capacitor/ios' + pod 'CapacitorCordova', :path => '../node_modules/@capacitor/ios' +end + +target 'Plugin' do + capacitor_pods + pod 'AppCenter/Crashes', '4.1.0' +end + +target 'PluginTests' do + capacitor_pods +end diff --git a/appcenter-crashes/package.json b/appcenter-crashes/package.json new file mode 100644 index 0000000..6f0a5b6 --- /dev/null +++ b/appcenter-crashes/package.json @@ -0,0 +1,78 @@ +{ + "name": "@capacitor-community/appcenter-crashes", + "version": "0.1.0", + "description": "App Center Crashes records the state of the app and device and automatically generates a crash log.", + "main": "dist/plugin.cjs.js", + "module": "dist/esm/index.js", + "types": "dist/esm/index.d.ts", + "unpkg": "dist/plugin.js", + "files": [ + "android/src/main/", + "android/build.gradle", + "dist/", + "ios/Plugin/", + "CapacitorCommunityAppcenterCrashes.podspec" + ], + "author": "johnborges", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/capacitor-community/appcenter-sdk-capacitor/tree/master/appcenter-crashes.git" + }, + "bugs": { + "url": "https://github.com/capacitor-community/appcenter-sdk-capacitor/tree/master/appcenter-crashes/issues" + }, + "keywords": [ + "capacitor", + "plugin", + "native" + ], + "scripts": { + "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", + "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..", + "verify:android": "cd android && ./gradlew clean build test && cd ..", + "verify:web": "npm run build", + "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", + "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- autocorrect --format", + "eslint": "eslint . --ext ts", + "prettier": "prettier \"**/*.{css,html,ts,js,java}\"", + "swiftlint": "node-swiftlint", + "docgen": "docgen --api AppCenterCrashesPlugin --output-readme README.md --output-json dist/docs.json", + "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.js", + "clean": "rimraf ./dist", + "watch": "tsc --watch", + "prepublishOnly": "npm run build" + }, + "devDependencies": { + "@capacitor/android": "next", + "@capacitor/core": "next", + "@capacitor/docgen": "^0.0.10", + "@capacitor/ios": "next", + "@ionic/eslint-config": "^0.3.0", + "@ionic/prettier-config": "^1.0.1", + "@ionic/swiftlint-config": "^1.1.2", + "eslint": "^7.11.0", + "prettier": "~2.2.0", + "prettier-plugin-java": "~1.0.0", + "rimraf": "^3.0.2", + "rollup": "^2.32.0", + "swiftlint": "^1.0.1", + "typescript": "~4.0.3" + }, + "peerDependencies": { + "@capacitor/core": "next" + }, + "prettier": "@ionic/prettier-config", + "swiftlint": "@ionic/swiftlint-config", + "eslintConfig": { + "extends": "@ionic/eslint-config/recommended" + }, + "capacitor": { + "ios": { + "src": "ios" + }, + "android": { + "src": "android" + } + } +} diff --git a/appcenter-crashes/rollup.config.js b/appcenter-crashes/rollup.config.js new file mode 100644 index 0000000..96a08b7 --- /dev/null +++ b/appcenter-crashes/rollup.config.js @@ -0,0 +1,22 @@ +export default { + input: 'dist/esm/index.js', + output: [ + { + file: 'dist/plugin.js', + format: 'iife', + name: 'capacitorAppCenterCrashes', + globals: { + '@capacitor/core': 'capacitorExports', + }, + sourcemap: true, + inlineDynamicImports: true, + }, + { + file: 'dist/plugin.cjs.js', + format: 'cjs', + sourcemap: true, + inlineDynamicImports: true, + }, + ], + external: ['@capacitor/core'], +}; diff --git a/appcenter-crashes/src/definitions.ts b/appcenter-crashes/src/definitions.ts new file mode 100644 index 0000000..24d1d2b --- /dev/null +++ b/appcenter-crashes/src/definitions.ts @@ -0,0 +1,3 @@ +export interface AppCenterCrashesPlugin { + echo(options: { value: string }): Promise<{ value: string }>; +} diff --git a/appcenter-crashes/src/index.ts b/appcenter-crashes/src/index.ts new file mode 100644 index 0000000..56d74f0 --- /dev/null +++ b/appcenter-crashes/src/index.ts @@ -0,0 +1,13 @@ +import { registerPlugin } from '@capacitor/core'; + +import type { AppCenterCrashesPlugin } from './definitions'; + +const AppCenterCrashes = registerPlugin( + 'AppCenterCrashes', + { + web: () => import('./web').then(m => new m.AppCenterCrashesWeb()), + }, +); + +export * from './definitions'; +export { AppCenterCrashes }; diff --git a/appcenter-crashes/src/web.ts b/appcenter-crashes/src/web.ts new file mode 100644 index 0000000..865cab0 --- /dev/null +++ b/appcenter-crashes/src/web.ts @@ -0,0 +1,12 @@ +import { WebPlugin } from '@capacitor/core'; + +import type { AppCenterCrashesPlugin } from './definitions'; + +export class AppCenterCrashesWeb + extends WebPlugin + implements AppCenterCrashesPlugin { + async echo(options: { value: string }): Promise<{ value: string }> { + console.log('ECHO', options); + return options; + } +} diff --git a/appcenter-crashes/tsconfig.json b/appcenter-crashes/tsconfig.json new file mode 100644 index 0000000..85ae95d --- /dev/null +++ b/appcenter-crashes/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "allowUnreachableCode": false, + "declaration": true, + "esModuleInterop": true, + "lib": ["dom", "es2017"], + "module": "esnext", + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "outDir": "dist/esm", + "pretty": true, + "sourceMap": true, + "strict": true, + "target": "es2017" + }, + "files": ["src/index.ts"] +} diff --git a/lerna.json b/lerna.json index 27a9499..f7bb626 100644 --- a/lerna.json +++ b/lerna.json @@ -2,6 +2,7 @@ "packages": [ "appcenter-shared", "appcenter-analytics", + "appcenter-crashes", "example" ], "command": { From 00f772375d464b65bb4d46cb9fff3b481721735c Mon Sep 17 00:00:00 2001 From: John Borges Date: Fri, 2 Apr 2021 13:36:00 -0400 Subject: [PATCH 02/27] feat(crashes): add utility class for JS conversion --- .../ios/Plugin.xcodeproj/project.pbxproj | 4 + .../ios/Plugin/AppCenterCrashesUtil.swift | 151 ++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 appcenter-crashes/ios/Plugin/AppCenterCrashesUtil.swift diff --git a/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj b/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj index cfd29d4..3cc3c13 100644 --- a/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj +++ b/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFFA52020D75100D50D53 /* Capacitor.framework */; }; 50ADFFA82020EE4F00D50D53 /* AppCenterCrashesPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* AppCenterCrashesPlugin.m */; }; 50E1A94820377CB70090CE1A /* AppCenterCrashesPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* AppCenterCrashesPlugin.swift */; }; + 6C68FCA62614B54E00BF2B4E /* AppCenterCrashesUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C68FCA52614B54E00BF2B4E /* AppCenterCrashesUtil.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -41,6 +42,7 @@ 50ADFFA72020EE4F00D50D53 /* AppCenterCrashesPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppCenterCrashesPlugin.m; sourceTree = ""; }; 50E1A94720377CB70090CE1A /* AppCenterCrashesPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCenterCrashesPlugin.swift; sourceTree = ""; }; 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = ""; }; + 6C68FCA52614B54E00BF2B4E /* AppCenterCrashesUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCenterCrashesUtil.swift; sourceTree = ""; }; 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = ""; }; 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = ""; }; @@ -97,6 +99,7 @@ 50ADFF8B201F53D600D50D53 /* AppCenterCrashesPlugin.h */, 50ADFFA72020EE4F00D50D53 /* AppCenterCrashesPlugin.m */, 50ADFF8C201F53D600D50D53 /* Info.plist */, + 6C68FCA52614B54E00BF2B4E /* AppCenterCrashesUtil.swift */, ); path = Plugin; sourceTree = ""; @@ -308,6 +311,7 @@ files = ( 50E1A94820377CB70090CE1A /* AppCenterCrashesPlugin.swift in Sources */, 2F98D68224C9AAE500613A4C /* AppCenterCrashes.swift in Sources */, + 6C68FCA62614B54E00BF2B4E /* AppCenterCrashesUtil.swift in Sources */, 50ADFFA82020EE4F00D50D53 /* AppCenterCrashesPlugin.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesUtil.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesUtil.swift new file mode 100644 index 0000000..fd5eba8 --- /dev/null +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesUtil.swift @@ -0,0 +1,151 @@ +import Foundation +import AppCenterCrashes + +/** + Utility class containing helpers for converting App Center objects. + */ +public class CrashesUtil { + static let kMSSdkName: String = "sdkName"; + static let kMSSdkVersion: String = "sdkVersion"; + static let kMSModel: String = "model"; + static let kMSOemName: String = "oemName"; + static let kMSOsName: String = "osName"; + static let kMSOsVersion: String = "osVersion"; + static let kMSOsBuild: String = "osBuild"; + static let kMSOsApiLevel: String = "osApiLevel"; + static let kMSLocale: String = "locale"; + static let kMSTimeZoneOffset: String = "timeZoneOffset"; + static let kMSScreenSize: String = "screenSize"; + static let kMSAppVersion: String = "appVersion"; + static let kMSCarrierName: String = "carrierName"; + static let kMSCarrierCountry: String = "carrierCountry"; + static let kMSAppBuild: String = "appBuild"; + static let kMSAppNamespace: String = "appNamespace"; + + /** + Serializes App Center Device properties to Dictionary + - Parameter device: App Center Device + - Returns Device Dictionary + */ + public func serializeDeviceToDictionary(device: Device) -> Dictionary { + var dict = [String: Any]() + + if !device.sdkName.isEmpty { + dict[CrashesUtil.kMSSdkName] = device.sdkName; + } + if !device.sdkName.isEmpty { + dict[CrashesUtil.kMSSdkVersion] = device.sdkVersion; + } + if !device.model.isEmpty { + dict[CrashesUtil.kMSModel] = device.model; + } + if !device.oemName.isEmpty { + dict[CrashesUtil.kMSOemName] = device.oemName; + } + if !device.osName.isEmpty { + dict[CrashesUtil.kMSOsName] = device.osName; + } + if !device.osVersion.isEmpty { + dict[CrashesUtil.kMSOsVersion] = device.osVersion; + } + if !device.osBuild.isEmpty { + dict[CrashesUtil.kMSOsBuild] = device.osBuild; + } + if device.osApiLevel != nil { + dict[CrashesUtil.kMSOsApiLevel] = device.osApiLevel!; + } + if !device.locale.isEmpty { + dict[CrashesUtil.kMSLocale] = device.locale; + } + if device.timeZoneOffset != nil { + dict[CrashesUtil.kMSTimeZoneOffset] = device.timeZoneOffset!; + } + if !device.screenSize.isEmpty { + dict[CrashesUtil.kMSScreenSize] = device.screenSize; + } + if !device.appVersion.isEmpty { + dict[CrashesUtil.kMSAppVersion] = device.appVersion; + } + if !device.carrierName.isEmpty { + dict[CrashesUtil.kMSCarrierName] = device.carrierName; + } + if !device.carrierCountry.isEmpty { + dict[CrashesUtil.kMSCarrierCountry] = device.carrierCountry; + } + if !device.appBuild.isEmpty { + dict[CrashesUtil.kMSAppBuild] = device.appBuild; + } + if !device.appNamespace.isEmpty { + dict[CrashesUtil.kMSAppNamespace] = device.appNamespace; + } + return dict; + } + + /** + Converts App Center ErrorReport to Dictionary + - Parameter report: App Center ErrorReport + - Returns JS optional Dictionary + */ + public func convertReportToJs(report: ErrorReport?) -> Dictionary? { + + guard let actualReport = report else { + return nil + } + + var dict = [String: Any]() + + let identifier: String = actualReport.incidentIdentifier + if !identifier.isEmpty { + dict["id"] = identifier + } + + let processIdentifier: UInt = actualReport.appProcessIdentifier + dict["appProcessIdentifier"] = String(processIdentifier) + + let startTime: Date? = actualReport.appStartTime + if startTime != nil { + dict["appStartTime"] = String(startTime!.timeIntervalSince1970) + } + + let errTime: Date? = actualReport.appErrorTime + if errTime != nil { + dict["appErrorTime"] = errTime!.timeIntervalSince1970 + } + + let exceptionName: String = actualReport.exceptionName + if !exceptionName.isEmpty { + dict["exceptionName"] = exceptionName + } + + let exceptionReason: String = actualReport.exceptionReason + if !exceptionReason.isEmpty { + dict["exceptionReason"] = exceptionReason + } + + let signal: String = actualReport.signal + if !signal.isEmpty { + dict["signal"] = signal + } + + dict["device"] = serializeDeviceToDictionary(device: actualReport.device) + + return dict + } + + /** + Converts arrat of App Center ErrorReports to a Dictionary + - Parameter reports: App Center ErrorReport + - Returns Array of Dictionaries + */ + public func convertReportsToJS (reports: [ErrorReport]) -> [[String: Any]] { + var jsReadyReports = [[String: Any]]() + for (index, value) in reports.enumerated() { + guard let convertedReport = convertReportToJs(report: value) else { + continue + } + jsReadyReports.append(convertedReport) + } + return jsReadyReports + } + +} From 2072505bcb5c4c7c48a33cde32150edc3b3dd490 Mon Sep 17 00:00:00 2001 From: John Borges Date: Thu, 22 Apr 2021 18:42:29 -0400 Subject: [PATCH 03/27] chore(crashes): update sdk --- .../CapacitorCommunityAppcenterCrashes.podspec | 6 +++--- appcenter-crashes/ios/Podfile | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/appcenter-crashes/CapacitorCommunityAppcenterCrashes.podspec b/appcenter-crashes/CapacitorCommunityAppcenterCrashes.podspec index 7e3f821..a2ad189 100644 --- a/appcenter-crashes/CapacitorCommunityAppcenterCrashes.podspec +++ b/appcenter-crashes/CapacitorCommunityAppcenterCrashes.podspec @@ -12,8 +12,8 @@ Pod::Spec.new do |s| s.source = { :git => package['repository']['url'], :tag => s.version.to_s } s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' s.ios.deployment_target = '12.0' - s.dependency 'Capacitor' - s.dependency 'AppCenter/Crashes' - s.static_framework = true s.swift_version = '5.1' + s.static_framework = true + s.dependency 'Capacitor' + s.dependency 'AppCenter/Crashes', '4.1.1' end diff --git a/appcenter-crashes/ios/Podfile b/appcenter-crashes/ios/Podfile index 71e1eda..b43d775 100644 --- a/appcenter-crashes/ios/Podfile +++ b/appcenter-crashes/ios/Podfile @@ -1,5 +1,6 @@ platform :ios, '12.0' + def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks use_frameworks! @@ -8,10 +9,12 @@ def capacitor_pods end target 'Plugin' do + use_frameworks! capacitor_pods - pod 'AppCenter/Crashes', '4.1.0' + pod 'AppCenter/Crashes', '4.1.1' end target 'PluginTests' do + use_frameworks! capacitor_pods end From 4e9482ef0070289460b016626cfcd61cfd973dd0 Mon Sep 17 00:00:00 2001 From: John Borges Date: Thu, 22 Apr 2021 18:43:12 -0400 Subject: [PATCH 04/27] feat(crashes): add utility class --- .../ios/Plugin/AppCenterCrashesUtil.swift | 278 +++++++++--------- 1 file changed, 139 insertions(+), 139 deletions(-) diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesUtil.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesUtil.swift index fd5eba8..7f8bee7 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesUtil.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesUtil.swift @@ -2,150 +2,150 @@ import Foundation import AppCenterCrashes /** - Utility class containing helpers for converting App Center objects. - */ + Utility class containing helpers for converting App Center objects. +*/ public class CrashesUtil { - static let kMSSdkName: String = "sdkName"; - static let kMSSdkVersion: String = "sdkVersion"; - static let kMSModel: String = "model"; - static let kMSOemName: String = "oemName"; - static let kMSOsName: String = "osName"; - static let kMSOsVersion: String = "osVersion"; - static let kMSOsBuild: String = "osBuild"; - static let kMSOsApiLevel: String = "osApiLevel"; - static let kMSLocale: String = "locale"; - static let kMSTimeZoneOffset: String = "timeZoneOffset"; - static let kMSScreenSize: String = "screenSize"; - static let kMSAppVersion: String = "appVersion"; - static let kMSCarrierName: String = "carrierName"; - static let kMSCarrierCountry: String = "carrierCountry"; - static let kMSAppBuild: String = "appBuild"; - static let kMSAppNamespace: String = "appNamespace"; - - /** - Serializes App Center Device properties to Dictionary - - Parameter device: App Center Device - - Returns Device Dictionary - */ - public func serializeDeviceToDictionary(device: Device) -> Dictionary { - var dict = [String: Any]() - - if !device.sdkName.isEmpty { - dict[CrashesUtil.kMSSdkName] = device.sdkName; - } - if !device.sdkName.isEmpty { - dict[CrashesUtil.kMSSdkVersion] = device.sdkVersion; - } - if !device.model.isEmpty { - dict[CrashesUtil.kMSModel] = device.model; - } - if !device.oemName.isEmpty { - dict[CrashesUtil.kMSOemName] = device.oemName; - } - if !device.osName.isEmpty { - dict[CrashesUtil.kMSOsName] = device.osName; - } - if !device.osVersion.isEmpty { - dict[CrashesUtil.kMSOsVersion] = device.osVersion; - } - if !device.osBuild.isEmpty { - dict[CrashesUtil.kMSOsBuild] = device.osBuild; - } - if device.osApiLevel != nil { - dict[CrashesUtil.kMSOsApiLevel] = device.osApiLevel!; - } - if !device.locale.isEmpty { - dict[CrashesUtil.kMSLocale] = device.locale; - } - if device.timeZoneOffset != nil { - dict[CrashesUtil.kMSTimeZoneOffset] = device.timeZoneOffset!; - } - if !device.screenSize.isEmpty { - dict[CrashesUtil.kMSScreenSize] = device.screenSize; - } - if !device.appVersion.isEmpty { - dict[CrashesUtil.kMSAppVersion] = device.appVersion; - } - if !device.carrierName.isEmpty { - dict[CrashesUtil.kMSCarrierName] = device.carrierName; - } - if !device.carrierCountry.isEmpty { - dict[CrashesUtil.kMSCarrierCountry] = device.carrierCountry; - } - if !device.appBuild.isEmpty { - dict[CrashesUtil.kMSAppBuild] = device.appBuild; - } - if !device.appNamespace.isEmpty { - dict[CrashesUtil.kMSAppNamespace] = device.appNamespace; - } - return dict; - } - - /** - Converts App Center ErrorReport to Dictionary - - Parameter report: App Center ErrorReport - - Returns JS optional Dictionary - */ - public func convertReportToJs(report: ErrorReport?) -> Dictionary? { + static let kMSSdkName: String = "sdkName"; + static let kMSSdkVersion: String = "sdkVersion"; + static let kMSModel: String = "model"; + static let kMSOemName: String = "oemName"; + static let kMSOsName: String = "osName"; + static let kMSOsVersion: String = "osVersion"; + static let kMSOsBuild: String = "osBuild"; + static let kMSOsApiLevel: String = "osApiLevel"; + static let kMSLocale: String = "locale"; + static let kMSTimeZoneOffset: String = "timeZoneOffset"; + static let kMSScreenSize: String = "screenSize"; + static let kMSAppVersion: String = "appVersion"; + static let kMSCarrierName: String = "carrierName"; + static let kMSCarrierCountry: String = "carrierCountry"; + static let kMSAppBuild: String = "appBuild"; + static let kMSAppNamespace: String = "appNamespace"; + + /** + Serializes App Center Device properties to Dictionary + - Parameter device: App Center Device + - Returns Device Dictionary + */ + public func serializeDeviceToDictionary(device: Device) -> Dictionary { + var dict = [String: Any]() + + if !device.sdkName.isEmpty { + dict[CrashesUtil.kMSSdkName] = device.sdkName; + } + if !device.sdkName.isEmpty { + dict[CrashesUtil.kMSSdkVersion] = device.sdkVersion; + } + if !device.model.isEmpty { + dict[CrashesUtil.kMSModel] = device.model; + } + if !device.oemName.isEmpty { + dict[CrashesUtil.kMSOemName] = device.oemName; + } + if !device.osName.isEmpty { + dict[CrashesUtil.kMSOsName] = device.osName; + } + if !device.osVersion.isEmpty { + dict[CrashesUtil.kMSOsVersion] = device.osVersion; + } + if !device.osBuild.isEmpty { + dict[CrashesUtil.kMSOsBuild] = device.osBuild; + } + if device.osApiLevel != nil { + dict[CrashesUtil.kMSOsApiLevel] = device.osApiLevel!; + } + if !device.locale.isEmpty { + dict[CrashesUtil.kMSLocale] = device.locale; + } + if device.timeZoneOffset != nil { + dict[CrashesUtil.kMSTimeZoneOffset] = device.timeZoneOffset!; + } + if !device.screenSize.isEmpty { + dict[CrashesUtil.kMSScreenSize] = device.screenSize; + } + if !device.appVersion.isEmpty { + dict[CrashesUtil.kMSAppVersion] = device.appVersion; + } + if !device.carrierName.isEmpty { + dict[CrashesUtil.kMSCarrierName] = device.carrierName; + } + if !device.carrierCountry.isEmpty { + dict[CrashesUtil.kMSCarrierCountry] = device.carrierCountry; + } + if !device.appBuild.isEmpty { + dict[CrashesUtil.kMSAppBuild] = device.appBuild; + } + if !device.appNamespace.isEmpty { + dict[CrashesUtil.kMSAppNamespace] = device.appNamespace; + } + return dict; + } + + /** + Converts App Center ErrorReport to Dictionary + - Parameter report: App Center ErrorReport + - Returns JS optional Dictionary + */ + public func convertReportToJs(report: ErrorReport?) -> Dictionary? { - guard let actualReport = report else { - return nil - } - - var dict = [String: Any]() - - let identifier: String = actualReport.incidentIdentifier - if !identifier.isEmpty { - dict["id"] = identifier - } - - let processIdentifier: UInt = actualReport.appProcessIdentifier - dict["appProcessIdentifier"] = String(processIdentifier) + guard let actualReport = report else { + return nil + } + + var dict = [String: Any]() + + let identifier: String = actualReport.incidentIdentifier + if !identifier.isEmpty { + dict["id"] = identifier + } + + let processIdentifier: UInt = actualReport.appProcessIdentifier + dict["appProcessIdentifier"] = String(processIdentifier) - let startTime: Date? = actualReport.appStartTime - if startTime != nil { - dict["appStartTime"] = String(startTime!.timeIntervalSince1970) - } + let startTime: Date? = actualReport.appStartTime + if startTime != nil { + dict["appStartTime"] = String(startTime!.timeIntervalSince1970) + } - let errTime: Date? = actualReport.appErrorTime - if errTime != nil { - dict["appErrorTime"] = errTime!.timeIntervalSince1970 - } - - let exceptionName: String = actualReport.exceptionName - if !exceptionName.isEmpty { - dict["exceptionName"] = exceptionName - } - - let exceptionReason: String = actualReport.exceptionReason - if !exceptionReason.isEmpty { - dict["exceptionReason"] = exceptionReason - } + let errTime: Date? = actualReport.appErrorTime + if errTime != nil { + dict["appErrorTime"] = errTime!.timeIntervalSince1970 + } + + let exceptionName: String = actualReport.exceptionName + if !exceptionName.isEmpty { + dict["exceptionName"] = exceptionName + } + + let exceptionReason: String = actualReport.exceptionReason + if !exceptionReason.isEmpty { + dict["exceptionReason"] = exceptionReason + } - let signal: String = actualReport.signal - if !signal.isEmpty { - dict["signal"] = signal - } + let signal: String = actualReport.signal + if !signal.isEmpty { + dict["signal"] = signal + } - dict["device"] = serializeDeviceToDictionary(device: actualReport.device) - - return dict - } - - /** - Converts arrat of App Center ErrorReports to a Dictionary - - Parameter reports: App Center ErrorReport - - Returns Array of Dictionaries - */ - public func convertReportsToJS (reports: [ErrorReport]) -> [[String: Any]] { - var jsReadyReports = [[String: Any]]() - for (index, value) in reports.enumerated() { - guard let convertedReport = convertReportToJs(report: value) else { - continue - } - jsReadyReports.append(convertedReport) - } - return jsReadyReports - } + dict["device"] = serializeDeviceToDictionary(device: actualReport.device) + + return dict + } + + /** + Converts arrat of App Center ErrorReports to a Dictionary + - Parameter reports: App Center ErrorReport + - Returns Array of Dictionaries + */ + public func convertReportsToJS (reports: [ErrorReport]) -> [[String: Any]] { + var jsReadyReports = [[String: Any]]() + for (index, value) in reports.enumerated() { + guard let convertedReport = convertReportToJs(report: value) else { + continue + } + jsReadyReports.append(convertedReport) + } + return jsReadyReports + } } From bfe2e470654ff4b2f22cd8f27b6d83d7197022f8 Mon Sep 17 00:00:00 2001 From: John Borges Date: Thu, 22 Apr 2021 18:45:04 -0400 Subject: [PATCH 05/27] chore(crashes): biolerplate setup --- appcenter-crashes/README.md | 32 +++- .../ios/Plugin.xcodeproj/project.pbxproj | 148 ++++++++++++------ .../ios/Plugin/AppCenterCrashes.swift | 7 - .../ios/Plugin/AppCenterCrashesBase.swift | 55 +++++++ .../ios/Plugin/AppCenterCrashesPlugin.m | 5 +- .../ios/Plugin/AppCenterCrashesPlugin.swift | 34 ++-- .../AppCenterCrashesPluginTests.swift | 2 +- appcenter-crashes/package.json | 2 +- appcenter-crashes/rollup.config.js | 2 +- appcenter-crashes/src/definitions.ts | 92 ++++++++++- appcenter-crashes/src/index.ts | 10 +- appcenter-crashes/src/web.ts | 14 +- example/ios/App/App/capacitor.config.json | 3 +- 13 files changed, 316 insertions(+), 90 deletions(-) delete mode 100644 appcenter-crashes/ios/Plugin/AppCenterCrashes.swift create mode 100644 appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift diff --git a/appcenter-crashes/README.md b/appcenter-crashes/README.md index fbcbc59..db99453 100644 --- a/appcenter-crashes/README.md +++ b/appcenter-crashes/README.md @@ -13,25 +13,45 @@ npx cap sync -* [`echo(...)`](#echo) +* [`isEnabled()`](#isenabled) +* [`setEnable(...)`](#setenable) -### echo(...) +### isEnabled() ```typescript -echo(options: { value: string; }) => any +isEnabled() => any ``` -| Param | Type | -| ------------- | ------------------------------- | -| **`options`** | { value: string; } | +Check if Crashes is enabled or not. **Returns:** any +**Since:** 0.1.0 + +-------------------- + + +### setEnable(...) + +```typescript +setEnable(options: { shouldEnable: boolean; }) => any +``` + +You can enable and disable App Center Crashes at runtime. If you disable it, the SDK won't do any crash reporting for the app. + +| Param | Type | +| ------------- | --------------------------------------- | +| **`options`** | { shouldEnable: boolean; } | + +**Returns:** any + +**Since:** 0.1.0 + -------------------- diff --git a/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj b/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj index 3cc3c13..1e5357c 100644 --- a/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj +++ b/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj @@ -7,9 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */; }; - 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */; }; - 2F98D68224C9AAE500613A4C /* AppCenterCrashes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F98D68124C9AAE400613A4C /* AppCenterCrashes.swift */; }; + 2F98D68224C9AAE500613A4C /* AppCenterCrashesBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F98D68124C9AAE400613A4C /* AppCenterCrashesBase.swift */; }; 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFF88201F53D600D50D53 /* Plugin.framework */; }; 50ADFF97201F53D600D50D53 /* AppCenterCrashesPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFF96201F53D600D50D53 /* AppCenterCrashesPluginTests.swift */; }; 50ADFF99201F53D600D50D53 /* AppCenterCrashesPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 50ADFF8B201F53D600D50D53 /* AppCenterCrashesPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -17,6 +15,8 @@ 50ADFFA82020EE4F00D50D53 /* AppCenterCrashesPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* AppCenterCrashesPlugin.m */; }; 50E1A94820377CB70090CE1A /* AppCenterCrashesPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* AppCenterCrashesPlugin.swift */; }; 6C68FCA62614B54E00BF2B4E /* AppCenterCrashesUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C68FCA52614B54E00BF2B4E /* AppCenterCrashesUtil.swift */; }; + 8104D3ED4B9FB3B83058F9D2 /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F1DF599EC8A36495C7A2B703 /* Pods_Plugin.framework */; }; + CF6458C6E816A207086AD72A /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E3F8D18BE010E80267B8A2C7 /* Pods_PluginTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -30,8 +30,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 2F98D68124C9AAE400613A4C /* AppCenterCrashes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCenterCrashes.swift; sourceTree = ""; }; - 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 2F98D68124C9AAE400613A4C /* AppCenterCrashesBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCenterCrashesBase.swift; sourceTree = ""; }; 50ADFF88201F53D600D50D53 /* Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50ADFF8B201F53D600D50D53 /* AppCenterCrashesPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppCenterCrashesPlugin.h; sourceTree = ""; }; 50ADFF8C201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -41,12 +40,15 @@ 50ADFFA52020D75100D50D53 /* Capacitor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Capacitor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50ADFFA72020EE4F00D50D53 /* AppCenterCrashesPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppCenterCrashesPlugin.m; sourceTree = ""; }; 50E1A94720377CB70090CE1A /* AppCenterCrashesPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCenterCrashesPlugin.swift; sourceTree = ""; }; - 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = ""; }; + 6C24BE27262F16B000E0E3CF /* AppCenterCrashes.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = AppCenterCrashes.xcframework; path = "Pods/AppCenter/AppCenter-SDK-Apple/AppCenterCrashes.xcframework"; sourceTree = ""; }; 6C68FCA52614B54E00BF2B4E /* AppCenterCrashesUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCenterCrashesUtil.swift; sourceTree = ""; }; - 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = ""; }; - 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; - F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = ""; }; - F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6CBFD270262FB25500211EBE /* AppCenter.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = AppCenter.xcframework; path = "Pods/AppCenter/AppCenter-SDK-Apple/AppCenter.xcframework"; sourceTree = ""; }; + 70341DA8E7DFB356E0F03B13 /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = ""; }; + 9B11203E0C8AD3BD5C1104F4 /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = ""; }; + D64B0D06D9D942749BA630B0 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = ""; }; + E3F8D18BE010E80267B8A2C7 /* Pods_PluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F1DF599EC8A36495C7A2B703 /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F436D740E11CC85A1BF4F5FE /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -55,7 +57,7 @@ buildActionMask = 2147483647; files = ( 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */, - 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */, + 8104D3ED4B9FB3B83058F9D2 /* Pods_Plugin.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -64,7 +66,7 @@ buildActionMask = 2147483647; files = ( 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */, - 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */, + CF6458C6E816A207086AD72A /* Pods_PluginTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -77,8 +79,8 @@ 50ADFF8A201F53D600D50D53 /* Plugin */, 50ADFF95201F53D600D50D53 /* PluginTests */, 50ADFF89201F53D600D50D53 /* Products */, - 8C8E7744173064A9F6D438E3 /* Pods */, A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */, + B0BBFEDEB32ECE96C2AC221E /* Pods */, ); sourceTree = ""; }; @@ -95,7 +97,7 @@ isa = PBXGroup; children = ( 50E1A94720377CB70090CE1A /* AppCenterCrashesPlugin.swift */, - 2F98D68124C9AAE400613A4C /* AppCenterCrashes.swift */, + 2F98D68124C9AAE400613A4C /* AppCenterCrashesBase.swift */, 50ADFF8B201F53D600D50D53 /* AppCenterCrashesPlugin.h */, 50ADFFA72020EE4F00D50D53 /* AppCenterCrashesPlugin.m */, 50ADFF8C201F53D600D50D53 /* Info.plist */, @@ -113,25 +115,27 @@ path = PluginTests; sourceTree = ""; }; - 8C8E7744173064A9F6D438E3 /* Pods */ = { + A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */ = { isa = PBXGroup; children = ( - 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */, - 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */, - 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */, - F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */, + 6CBFD270262FB25500211EBE /* AppCenter.xcframework */, + 6C24BE27262F16B000E0E3CF /* AppCenterCrashes.xcframework */, + 50ADFFA52020D75100D50D53 /* Capacitor.framework */, + F1DF599EC8A36495C7A2B703 /* Pods_Plugin.framework */, + E3F8D18BE010E80267B8A2C7 /* Pods_PluginTests.framework */, ); - name = Pods; + name = Frameworks; sourceTree = ""; }; - A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */ = { + B0BBFEDEB32ECE96C2AC221E /* Pods */ = { isa = PBXGroup; children = ( - 50ADFFA52020D75100D50D53 /* Capacitor.framework */, - 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */, - F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */, + 70341DA8E7DFB356E0F03B13 /* Pods-Plugin.debug.xcconfig */, + 9B11203E0C8AD3BD5C1104F4 /* Pods-Plugin.release.xcconfig */, + F436D740E11CC85A1BF4F5FE /* Pods-PluginTests.debug.xcconfig */, + D64B0D06D9D942749BA630B0 /* Pods-PluginTests.release.xcconfig */, ); - name = Frameworks; + path = Pods; sourceTree = ""; }; /* End PBXGroup section */ @@ -152,7 +156,7 @@ isa = PBXNativeTarget; buildConfigurationList = 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */; buildPhases = ( - AB5B3E54B4E897F32C2279DA /* [CP] Check Pods Manifest.lock */, + 74EAEA0DD19E6367C2854FE6 /* [CP] Check Pods Manifest.lock */, 50ADFF83201F53D600D50D53 /* Sources */, 50ADFF84201F53D600D50D53 /* Frameworks */, 50ADFF85201F53D600D50D53 /* Headers */, @@ -171,11 +175,11 @@ isa = PBXNativeTarget; buildConfigurationList = 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */; buildPhases = ( - 0596884F929ED6F1DE134961 /* [CP] Check Pods Manifest.lock */, + 3242696D7885CF3134BF4673 /* [CP] Check Pods Manifest.lock */, 50ADFF8D201F53D600D50D53 /* Sources */, 50ADFF8E201F53D600D50D53 /* Frameworks */, 50ADFF8F201F53D600D50D53 /* Resources */, - 8E97F58B69A94C6503FC9C85 /* [CP] Embed Pods Frameworks */, + B2618EC7C9CA8E48762C733E /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -246,16 +250,20 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 0596884F929ED6F1DE134961 /* [CP] Check Pods Manifest.lock */ = { + 3242696D7885CF3134BF4673 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-PluginTests-checkManifestLockResult.txt", ); @@ -264,42 +272,46 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 8E97F58B69A94C6503FC9C85 /* [CP] Embed Pods Frameworks */ = { + 74EAEA0DD19E6367C2854FE6 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/Capacitor/Capacitor.framework", - "${BUILT_PRODUCTS_DIR}/CapacitorCordova/Cordova.framework", + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( ); - name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Capacitor.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cordova.framework", + "$(DERIVED_FILE_DIR)/Pods-Plugin-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - AB5B3E54B4E897F32C2279DA /* [CP] Check Pods Manifest.lock */ = { + B2618EC7C9CA8E48762C733E /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", + "${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Capacitor/Capacitor.framework", + "${BUILT_PRODUCTS_DIR}/CapacitorCordova/Cordova.framework", ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Plugin-checkManifestLockResult.txt", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Capacitor.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cordova.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -310,7 +322,7 @@ buildActionMask = 2147483647; files = ( 50E1A94820377CB70090CE1A /* AppCenterCrashesPlugin.swift in Sources */, - 2F98D68224C9AAE500613A4C /* AppCenterCrashes.swift in Sources */, + 2F98D68224C9AAE500613A4C /* AppCenterCrashesBase.swift in Sources */, 6C68FCA62614B54E00BF2B4E /* AppCenterCrashesUtil.swift in Sources */, 50ADFFA82020EE4F00D50D53 /* AppCenterCrashesPlugin.m in Sources */, ); @@ -462,7 +474,7 @@ }; 50ADFF9D201F53D600D50D53 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */; + baseConfigurationReference = 70341DA8E7DFB356E0F03B13 /* Pods-Plugin.debug.xcconfig */; buildSettings = { CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; @@ -476,6 +488,26 @@ IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = ( + "$(inherited)", + "-l\"c++\"", + "-l\"sqlite3\"", + "-l\"z\"", + "-framework", + "\"Capacitor\"", + "-framework", + "\"Cordova\"", + "-framework", + "\"CoreTelephony\"", + "-framework", + "\"Foundation\"", + "-framework", + "\"SystemConfiguration\"", + "-framework", + "\"UIKit\"", + "-framework", + "\"WebKit\"", + ); PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -487,7 +519,7 @@ }; 50ADFF9E201F53D600D50D53 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */; + baseConfigurationReference = 9B11203E0C8AD3BD5C1104F4 /* Pods-Plugin.release.xcconfig */; buildSettings = { CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; @@ -501,6 +533,26 @@ IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "$(inherited)", + "-l\"c++\"", + "-l\"sqlite3\"", + "-l\"z\"", + "-framework", + "\"Capacitor\"", + "-framework", + "\"Cordova\"", + "-framework", + "\"CoreTelephony\"", + "-framework", + "\"Foundation\"", + "-framework", + "\"SystemConfiguration\"", + "-framework", + "\"UIKit\"", + "-framework", + "\"WebKit\"", + ); PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.Plugin; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -511,7 +563,7 @@ }; 50ADFFA0201F53D600D50D53 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */; + baseConfigurationReference = F436D740E11CC85A1BF4F5FE /* Pods-PluginTests.debug.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = PluginTests/Info.plist; @@ -525,7 +577,7 @@ }; 50ADFFA1201F53D600D50D53 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */; + baseConfigurationReference = D64B0D06D9D942749BA630B0 /* Pods-PluginTests.release.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = PluginTests/Info.plist; diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashes.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashes.swift deleted file mode 100644 index 98ff9f8..0000000 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashes.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -@objc public class AppCenterCrashes: NSObject { - @objc public func echo(_ value: String) -> String { - return value - } -} diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift new file mode 100644 index 0000000..202d45b --- /dev/null +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift @@ -0,0 +1,55 @@ +import Foundation +import Capacitor +import AppCenter +import AppCenterCrashes + +// need to move most of this functionality to a shared module accros all AppCenter plugins +@objc public class AppCenterCrashesBase: NSObject { + + var appSecret: String? + var wrapperSdk: WrapperSdk? + + public func enable(_ flag: Bool) { + Crashes.enabled = flag + } + + public func isEnabled() -> Bool { + return Crashes.enabled + } + + public func configureWithSettings(_ secret: String) { + AppCenter.logLevel = .verbose + + if AppCenter.isConfigured { + AppCenter.startService(Crashes.self) + return + } + + let wrapperSdk = WrapperSdk(wrapperSdkVersion: "0.1.0", wrapperSdkName: "appcenter.capacitor", wrapperRuntimeVersion: nil, liveUpdateReleaseLabel: nil, liveUpdateDeploymentKey: nil, liveUpdatePackageHash: nil) + + setWrapperSdk(wrapperSdk!) + + AppCenter.start(withAppSecret: getAppSecret(secret), services: [Crashes.self]) + } + + func setAppSecret(_ secret: String) { + appSecret = secret + } + + func getAppSecret(_ secret: String) -> String { + if appSecret == nil { + setAppSecret(secret) + } + return appSecret! + } + + func getWrapperSdk() -> WrapperSdk { + return wrapperSdk! + } + + func setWrapperSdk(_ sdk: WrapperSdk) { + wrapperSdk = sdk + AppCenter.wrapperSdk = sdk + } + +} diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m index 50e474d..a498805 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m @@ -3,6 +3,7 @@ // Define the plugin using the CAP_PLUGIN Macro, and // each method the plugin supports using the CAP_PLUGIN_METHOD macro. -CAP_PLUGIN(AppCenterCrashesPlugin, "AppCenterCrashes", - CAP_PLUGIN_METHOD(echo, CAPPluginReturnPromise); +CAP_PLUGIN(AppCenterCrashesPlugin, "CrashesPlugin", + CAP_PLUGIN_METHOD(setEnable, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(isEnabled, CAPPluginReturnPromise); ) diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift index 86f21de..a0e0f07 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift @@ -1,18 +1,32 @@ import Foundation import Capacitor -/** - * Please read the Capacitor iOS Plugin Development Guide - * here: https://capacitorjs.com/docs/plugins/ios - */ @objc(AppCenterCrashesPlugin) public class AppCenterCrashesPlugin: CAPPlugin { - private let implementation = AppCenterCrashes() + private let implementation = AppCenterCrashesBase() + + public override func load() { + + print("[AppCenterCrashesPlugin] load") + + let appSecret = self.bridge?.config.getString("AppCenter.iosAppSecret") ?? "" + let enableInJs = getConfigValue("enableInJs") as? Bool ?? false + + implementation.configureWithSettings(appSecret) + + if enableInJs { + // Avoid starting an analytics session since it will get enabled in JS + implementation.enable(false) + } + } - @objc func echo(_ call: CAPPluginCall) { - let value = call.getString("value") ?? "" - call.resolve([ - "value": implementation.echo(value) - ]) + @objc func setEnable(_ call: CAPPluginCall) { + implementation.enable(call.getBool("shouldEnable") ?? false) + call.resolve() + } + + @objc func isEnabled(_ call: CAPPluginCall) { + call.resolve(["value": implementation.isEnabled()]) + call.resolve() } } diff --git a/appcenter-crashes/ios/PluginTests/AppCenterCrashesPluginTests.swift b/appcenter-crashes/ios/PluginTests/AppCenterCrashesPluginTests.swift index 28d7992..0e11bb2 100644 --- a/appcenter-crashes/ios/PluginTests/AppCenterCrashesPluginTests.swift +++ b/appcenter-crashes/ios/PluginTests/AppCenterCrashesPluginTests.swift @@ -16,7 +16,7 @@ class AppCenterCrashesTests: XCTestCase { // This is an example of a functional test case for a plugin. // Use XCTAssert and related functions to verify your tests produce the correct results. - let implementation = AppCenterCrashes() + let implementation = AppCenterCrashesBase() let value = "Hello, World!" let result = implementation.echo(value) diff --git a/appcenter-crashes/package.json b/appcenter-crashes/package.json index 6f0a5b6..01eac8c 100644 --- a/appcenter-crashes/package.json +++ b/appcenter-crashes/package.json @@ -37,7 +37,7 @@ "eslint": "eslint . --ext ts", "prettier": "prettier \"**/*.{css,html,ts,js,java}\"", "swiftlint": "node-swiftlint", - "docgen": "docgen --api AppCenterCrashesPlugin --output-readme README.md --output-json dist/docs.json", + "docgen": "docgen --api CrashesPlugin --output-readme README.md --output-json dist/docs.json", "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.js", "clean": "rimraf ./dist", "watch": "tsc --watch", diff --git a/appcenter-crashes/rollup.config.js b/appcenter-crashes/rollup.config.js index 96a08b7..4644b33 100644 --- a/appcenter-crashes/rollup.config.js +++ b/appcenter-crashes/rollup.config.js @@ -4,7 +4,7 @@ export default { { file: 'dist/plugin.js', format: 'iife', - name: 'capacitorAppCenterCrashes', + name: 'capacitorCrashes', globals: { '@capacitor/core': 'capacitorExports', }, diff --git a/appcenter-crashes/src/definitions.ts b/appcenter-crashes/src/definitions.ts index 24d1d2b..936731c 100644 --- a/appcenter-crashes/src/definitions.ts +++ b/appcenter-crashes/src/definitions.ts @@ -1,3 +1,91 @@ -export interface AppCenterCrashesPlugin { - echo(options: { value: string }): Promise<{ value: string }>; +export enum UserConfirmation { + DONT_SEND = 0, + SEND = 1, + ALWAYS_SEND = 2 } + +export interface Device { + sdkName: string; + sdkVersion: string; + model: string; + oemName: string; + osName: string; + osVersion: string; + osBuild: string; + osApiLevel?: number; + locale: string; + timeZoneOffset: number; + screenSize?: string; + appVersion: string; + carrierName?: string; + carrierCountry?: string; + appBuild: string; + appNamespace: string; +} + +export interface ErrorReport { + id: string; + threadName?: string; + appErrorTime: string | number; + appStartTime: string | number; + exception?: string; + exceptionReason?: string; + device: Device; + signal?: string; + appProcessIdentifier?: number; +} + +export interface CrashesListener { + onBeforeSending?: (report: ErrorReport) => void; + onSendingSucceeded?: (report: ErrorReport) => void; + onSendingFailed?: (report: ErrorReport) => void; + getErrorAttachments?: (report: ErrorReport) => Promise; + shouldProcess?: (report: ErrorReport) => boolean; + shouldAwaitUserConfirmation?: () => boolean; +} + +export class ErrorAttachmentLog { + // Create text attachment for an error report + public static attachmentWithText(text: string, fileName?: string): ErrorAttachmentLog { + return { text, fileName }; + } + // Create binary attachment for an error report, binary must be passed as a base64 string + public static attachmentWithBinary( + data: string, + fileName: string | null, + contentType: string + ): ErrorAttachmentLog { + return { data, fileName, contentType }; + } +} + +export interface CrashesPlugin { + /** + * Check if Crashes is enabled or not. + * @returns {Promise<{value: boolean}>} + * @since 0.1.0 + * @example + * import Crashes from '@capacitor-community/appcenter-crashes'; + * + * const { value: enabled } = await Crashes.isEnabled(); + */ + isEnabled(): Promise<{value: boolean}>; + /** + * You can enable and disable App Center Crashes at runtime. If you disable it, the SDK won't do any crash reporting for the app. + * @param {shouldEnable: boolean} options + * @since 0.1.0 + * @example + * import Crashes from '@capacitor-community/appcenter-crashes'; + + * await Crashes.enable({shouldEnable: true}); + */ + setEnable(options: {shouldEnable: boolean}): Promise; +} + +// convert +// export function generateTestCrash(): Promise; +// export function hasCrashedInLastSession(): Promise; +// export function hasReceivedMemoryWarningInLastSession(): Promise; +// export function lastSessionCrashReport(): Promise; +// export function notifyUserConfirmation(userConfirmation: UserConfirmation): void; +// export function setListener(crashesListener: CrashesListener): Promise; diff --git a/appcenter-crashes/src/index.ts b/appcenter-crashes/src/index.ts index 56d74f0..f29f395 100644 --- a/appcenter-crashes/src/index.ts +++ b/appcenter-crashes/src/index.ts @@ -1,13 +1,13 @@ import { registerPlugin } from '@capacitor/core'; -import type { AppCenterCrashesPlugin } from './definitions'; +import type { CrashesPlugin } from './definitions'; -const AppCenterCrashes = registerPlugin( - 'AppCenterCrashes', +const Crashes = registerPlugin( + 'Crashes', { - web: () => import('./web').then(m => new m.AppCenterCrashesWeb()), + web: () => import('./web').then(m => new m.CrashesWeb()), }, ); export * from './definitions'; -export { AppCenterCrashes }; +export default Crashes; diff --git a/appcenter-crashes/src/web.ts b/appcenter-crashes/src/web.ts index 865cab0..25bd8b5 100644 --- a/appcenter-crashes/src/web.ts +++ b/appcenter-crashes/src/web.ts @@ -1,12 +1,14 @@ import { WebPlugin } from '@capacitor/core'; -import type { AppCenterCrashesPlugin } from './definitions'; +import type { CrashesPlugin } from './definitions'; -export class AppCenterCrashesWeb +export class CrashesWeb extends WebPlugin - implements AppCenterCrashesPlugin { - async echo(options: { value: string }): Promise<{ value: string }> { - console.log('ECHO', options); - return options; + implements CrashesPlugin { + isEnabled(): Promise<{ value: boolean; }> { + throw this.unimplemented('Not supported on web.'); + } + setEnable(): Promise { + throw this.unimplemented('Not supported on web.'); } } diff --git a/example/ios/App/App/capacitor.config.json b/example/ios/App/App/capacitor.config.json index 8e3adc2..5b17fa4 100644 --- a/example/ios/App/App/capacitor.config.json +++ b/example/ios/App/App/capacitor.config.json @@ -5,9 +5,10 @@ "bundledWebRuntime": false, "plugins": { "Analytics": { - "iosAppSecret": "fb3a28d5-1ed9-401c-b06a-0379f66c8650", + "iosAppSecret": "0000-0000-0000-0000-000000000000", "androidAppSecret": "0000-0000-0000-0000-000000000000", "transmissionInterval": "10", + "enableInJs": false } } } From ae2e3317188724bc544c7fed97758d30c6b73ab9 Mon Sep 17 00:00:00 2001 From: John Borges Date: Thu, 10 Jun 2021 20:09:33 -0400 Subject: [PATCH 06/27] chore(crashes): use v3 capacitor --- appcenter-crashes/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appcenter-crashes/package.json b/appcenter-crashes/package.json index 01eac8c..4d1eba1 100644 --- a/appcenter-crashes/package.json +++ b/appcenter-crashes/package.json @@ -44,10 +44,10 @@ "prepublishOnly": "npm run build" }, "devDependencies": { - "@capacitor/android": "next", - "@capacitor/core": "next", + "@capacitor/android": "3.0.0", + "@capacitor/core": "3.0.0", "@capacitor/docgen": "^0.0.10", - "@capacitor/ios": "next", + "@capacitor/ios": "3.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "^1.0.1", "@ionic/swiftlint-config": "^1.1.2", From 563bba2d31fe690f267e68e81b92bc26e655683c Mon Sep 17 00:00:00 2001 From: John Borges Date: Thu, 10 Jun 2021 20:11:24 -0400 Subject: [PATCH 07/27] refactor(crashes): use AppCenterCapacitorShared --- ...CapacitorCommunityAppcenterCrashes.podspec | 1 + .../ios/Plugin.xcodeproj/project.pbxproj | 52 ++++++++--------- .../ios/Plugin/AppCenterCrashesBase.swift | 58 ++++--------------- .../ios/Plugin/AppCenterCrashesPlugin.m | 4 +- .../ios/Plugin/AppCenterCrashesPlugin.swift | 34 +++++++---- appcenter-crashes/ios/Podfile | 4 +- appcenter-crashes/src/definitions.ts | 3 +- appcenter-crashes/src/index.ts | 9 +-- appcenter-crashes/src/web.ts | 2 +- 9 files changed, 69 insertions(+), 98 deletions(-) diff --git a/appcenter-crashes/CapacitorCommunityAppcenterCrashes.podspec b/appcenter-crashes/CapacitorCommunityAppcenterCrashes.podspec index a2ad189..2007dbc 100644 --- a/appcenter-crashes/CapacitorCommunityAppcenterCrashes.podspec +++ b/appcenter-crashes/CapacitorCommunityAppcenterCrashes.podspec @@ -15,5 +15,6 @@ Pod::Spec.new do |s| s.swift_version = '5.1' s.static_framework = true s.dependency 'Capacitor' + s.dependency 'AppCenterCapacitorShared', '0.3.0' s.dependency 'AppCenter/Crashes', '4.1.1' end diff --git a/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj b/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj index 1e5357c..be1b773 100644 --- a/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj +++ b/appcenter-crashes/ios/Plugin.xcodeproj/project.pbxproj @@ -14,9 +14,9 @@ 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFFA52020D75100D50D53 /* Capacitor.framework */; }; 50ADFFA82020EE4F00D50D53 /* AppCenterCrashesPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* AppCenterCrashesPlugin.m */; }; 50E1A94820377CB70090CE1A /* AppCenterCrashesPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* AppCenterCrashesPlugin.swift */; }; + 57110817E9EB026893490E3E /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49188A6F53B827D3174911BD /* Pods_Plugin.framework */; }; 6C68FCA62614B54E00BF2B4E /* AppCenterCrashesUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C68FCA52614B54E00BF2B4E /* AppCenterCrashesUtil.swift */; }; - 8104D3ED4B9FB3B83058F9D2 /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F1DF599EC8A36495C7A2B703 /* Pods_Plugin.framework */; }; - CF6458C6E816A207086AD72A /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E3F8D18BE010E80267B8A2C7 /* Pods_PluginTests.framework */; }; + DD483E8D78647AF16740E5A4 /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 160147C994EEF0AFE775D7BB /* Pods_PluginTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -30,7 +30,10 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 0F94A9C20D74688257CB4D47 /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = ""; }; + 160147C994EEF0AFE775D7BB /* Pods_PluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 2F98D68124C9AAE400613A4C /* AppCenterCrashesBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCenterCrashesBase.swift; sourceTree = ""; }; + 49188A6F53B827D3174911BD /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50ADFF88201F53D600D50D53 /* Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50ADFF8B201F53D600D50D53 /* AppCenterCrashesPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppCenterCrashesPlugin.h; sourceTree = ""; }; 50ADFF8C201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -40,15 +43,12 @@ 50ADFFA52020D75100D50D53 /* Capacitor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Capacitor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50ADFFA72020EE4F00D50D53 /* AppCenterCrashesPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppCenterCrashesPlugin.m; sourceTree = ""; }; 50E1A94720377CB70090CE1A /* AppCenterCrashesPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCenterCrashesPlugin.swift; sourceTree = ""; }; + 6BC57A7C026ED2F9519A4BED /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = ""; }; 6C24BE27262F16B000E0E3CF /* AppCenterCrashes.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = AppCenterCrashes.xcframework; path = "Pods/AppCenter/AppCenter-SDK-Apple/AppCenterCrashes.xcframework"; sourceTree = ""; }; 6C68FCA52614B54E00BF2B4E /* AppCenterCrashesUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCenterCrashesUtil.swift; sourceTree = ""; }; 6CBFD270262FB25500211EBE /* AppCenter.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = AppCenter.xcframework; path = "Pods/AppCenter/AppCenter-SDK-Apple/AppCenter.xcframework"; sourceTree = ""; }; - 70341DA8E7DFB356E0F03B13 /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = ""; }; - 9B11203E0C8AD3BD5C1104F4 /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = ""; }; - D64B0D06D9D942749BA630B0 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = ""; }; - E3F8D18BE010E80267B8A2C7 /* Pods_PluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - F1DF599EC8A36495C7A2B703 /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - F436D740E11CC85A1BF4F5FE /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; + 8F2B9A13CAB25D574E623D4B /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = ""; }; + C54F5D3230FD7EEF2B30EB82 /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -57,7 +57,7 @@ buildActionMask = 2147483647; files = ( 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */, - 8104D3ED4B9FB3B83058F9D2 /* Pods_Plugin.framework in Frameworks */, + 57110817E9EB026893490E3E /* Pods_Plugin.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -66,7 +66,7 @@ buildActionMask = 2147483647; files = ( 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */, - CF6458C6E816A207086AD72A /* Pods_PluginTests.framework in Frameworks */, + DD483E8D78647AF16740E5A4 /* Pods_PluginTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -121,8 +121,8 @@ 6CBFD270262FB25500211EBE /* AppCenter.xcframework */, 6C24BE27262F16B000E0E3CF /* AppCenterCrashes.xcframework */, 50ADFFA52020D75100D50D53 /* Capacitor.framework */, - F1DF599EC8A36495C7A2B703 /* Pods_Plugin.framework */, - E3F8D18BE010E80267B8A2C7 /* Pods_PluginTests.framework */, + 49188A6F53B827D3174911BD /* Pods_Plugin.framework */, + 160147C994EEF0AFE775D7BB /* Pods_PluginTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -130,10 +130,10 @@ B0BBFEDEB32ECE96C2AC221E /* Pods */ = { isa = PBXGroup; children = ( - 70341DA8E7DFB356E0F03B13 /* Pods-Plugin.debug.xcconfig */, - 9B11203E0C8AD3BD5C1104F4 /* Pods-Plugin.release.xcconfig */, - F436D740E11CC85A1BF4F5FE /* Pods-PluginTests.debug.xcconfig */, - D64B0D06D9D942749BA630B0 /* Pods-PluginTests.release.xcconfig */, + 0F94A9C20D74688257CB4D47 /* Pods-Plugin.debug.xcconfig */, + 8F2B9A13CAB25D574E623D4B /* Pods-Plugin.release.xcconfig */, + C54F5D3230FD7EEF2B30EB82 /* Pods-PluginTests.debug.xcconfig */, + 6BC57A7C026ED2F9519A4BED /* Pods-PluginTests.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -156,7 +156,7 @@ isa = PBXNativeTarget; buildConfigurationList = 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */; buildPhases = ( - 74EAEA0DD19E6367C2854FE6 /* [CP] Check Pods Manifest.lock */, + 86A8323D01A706EBE7777760 /* [CP] Check Pods Manifest.lock */, 50ADFF83201F53D600D50D53 /* Sources */, 50ADFF84201F53D600D50D53 /* Frameworks */, 50ADFF85201F53D600D50D53 /* Headers */, @@ -175,11 +175,11 @@ isa = PBXNativeTarget; buildConfigurationList = 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */; buildPhases = ( - 3242696D7885CF3134BF4673 /* [CP] Check Pods Manifest.lock */, + 652F216CA86DC09BFCF9B81F /* [CP] Check Pods Manifest.lock */, 50ADFF8D201F53D600D50D53 /* Sources */, 50ADFF8E201F53D600D50D53 /* Frameworks */, 50ADFF8F201F53D600D50D53 /* Resources */, - B2618EC7C9CA8E48762C733E /* [CP] Embed Pods Frameworks */, + D9A541174179A6D87384DF04 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -250,7 +250,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 3242696D7885CF3134BF4673 /* [CP] Check Pods Manifest.lock */ = { + 652F216CA86DC09BFCF9B81F /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -272,7 +272,7 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 74EAEA0DD19E6367C2854FE6 /* [CP] Check Pods Manifest.lock */ = { + 86A8323D01A706EBE7777760 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -294,7 +294,7 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - B2618EC7C9CA8E48762C733E /* [CP] Embed Pods Frameworks */ = { + D9A541174179A6D87384DF04 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -474,7 +474,7 @@ }; 50ADFF9D201F53D600D50D53 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 70341DA8E7DFB356E0F03B13 /* Pods-Plugin.debug.xcconfig */; + baseConfigurationReference = 0F94A9C20D74688257CB4D47 /* Pods-Plugin.debug.xcconfig */; buildSettings = { CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; @@ -519,7 +519,7 @@ }; 50ADFF9E201F53D600D50D53 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9B11203E0C8AD3BD5C1104F4 /* Pods-Plugin.release.xcconfig */; + baseConfigurationReference = 8F2B9A13CAB25D574E623D4B /* Pods-Plugin.release.xcconfig */; buildSettings = { CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; @@ -563,7 +563,7 @@ }; 50ADFFA0201F53D600D50D53 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = F436D740E11CC85A1BF4F5FE /* Pods-PluginTests.debug.xcconfig */; + baseConfigurationReference = C54F5D3230FD7EEF2B30EB82 /* Pods-PluginTests.debug.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = PluginTests/Info.plist; @@ -577,7 +577,7 @@ }; 50ADFFA1201F53D600D50D53 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D64B0D06D9D942749BA630B0 /* Pods-PluginTests.release.xcconfig */; + baseConfigurationReference = 6BC57A7C026ED2F9519A4BED /* Pods-PluginTests.release.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = PluginTests/Info.plist; diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift index 202d45b..a6e1f8c 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift @@ -3,53 +3,17 @@ import Capacitor import AppCenter import AppCenterCrashes -// need to move most of this functionality to a shared module accros all AppCenter plugins @objc public class AppCenterCrashesBase: NSObject { - var appSecret: String? - var wrapperSdk: WrapperSdk? - - public func enable(_ flag: Bool) { - Crashes.enabled = flag - } - - public func isEnabled() -> Bool { - return Crashes.enabled - } - - public func configureWithSettings(_ secret: String) { - AppCenter.logLevel = .verbose - - if AppCenter.isConfigured { - AppCenter.startService(Crashes.self) - return - } - - let wrapperSdk = WrapperSdk(wrapperSdkVersion: "0.1.0", wrapperSdkName: "appcenter.capacitor", wrapperRuntimeVersion: nil, liveUpdateReleaseLabel: nil, liveUpdateDeploymentKey: nil, liveUpdatePackageHash: nil) - - setWrapperSdk(wrapperSdk!) - - AppCenter.start(withAppSecret: getAppSecret(secret), services: [Crashes.self]) - } - - func setAppSecret(_ secret: String) { - appSecret = secret - } - - func getAppSecret(_ secret: String) -> String { - if appSecret == nil { - setAppSecret(secret) - } - return appSecret! - } - - func getWrapperSdk() -> WrapperSdk { - return wrapperSdk! - } - - func setWrapperSdk(_ sdk: WrapperSdk) { - wrapperSdk = sdk - AppCenter.wrapperSdk = sdk - } - + public func enable(_ flag: Bool) { + Crashes.enabled = flag + } + + public func isEnabled() -> Bool { + return Crashes.enabled + } + + public func start() { + AppCenter.startService(Crashes.self) + } } diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m index a498805..d33897b 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m @@ -3,7 +3,7 @@ // Define the plugin using the CAP_PLUGIN Macro, and // each method the plugin supports using the CAP_PLUGIN_METHOD macro. -CAP_PLUGIN(AppCenterCrashesPlugin, "CrashesPlugin", - CAP_PLUGIN_METHOD(setEnable, CAPPluginReturnPromise); +CAP_PLUGIN(CrashesPlugin, "Crashes", + CAP_PLUGIN_METHOD(setEnabled, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(isEnabled, CAPPluginReturnPromise); ) diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift index a0e0f07..a4cee83 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift @@ -1,32 +1,42 @@ import Foundation import Capacitor +import AppCenterCapacitorShared -@objc(AppCenterCrashesPlugin) -public class AppCenterCrashesPlugin: CAPPlugin { +@objc(CrashesPlugin) +public class CrashesPlugin: CAPPlugin { + private let implementation = AppCenterCrashesBase() public override func load() { - print("[AppCenterCrashesPlugin] load") + print("[CrashesPlugin] load") - let appSecret = self.bridge?.config.getString("AppCenter.iosAppSecret") ?? "" - let enableInJs = getConfigValue("enableInJs") as? Bool ?? false + AppCenterCapacitorShared.configureWithSettings() + + let config: NSDictionary = AppCenterCapacitorShared.getConfiguration() - implementation.configureWithSettings(appSecret) + // get Crashes config options + let enableInJs = config["CrashesEnableInJs"] as? Bool + let alwaysSendCrashes = config["CrashesAlwaysSend"] as? Bool - if enableInJs { - // Avoid starting an analytics session since it will get enabled in JS - implementation.enable(false) + if AppCenterCapacitorShared.isSdkConfigured() { + + implementation.start() + + // disable auto start of Crashes + if enableInJs ?? false { + implementation.enable(false) + } } } - @objc func setEnable(_ call: CAPPluginCall) { - implementation.enable(call.getBool("shouldEnable") ?? false) + @objc func setEnabled(_ call: CAPPluginCall) { + implementation.enable(call.getBool("shouldEnable") ?? false) call.resolve() } @objc func isEnabled(_ call: CAPPluginCall) { - call.resolve(["value": implementation.isEnabled()]) + call.resolve(["value": implementation.isEnabled()]) call.resolve() } } diff --git a/appcenter-crashes/ios/Podfile b/appcenter-crashes/ios/Podfile index b43d775..ccc23ff 100644 --- a/appcenter-crashes/ios/Podfile +++ b/appcenter-crashes/ios/Podfile @@ -1,6 +1,5 @@ platform :ios, '12.0' - def capacitor_pods # Comment the next line if you're not using Swift and don't want to use dynamic frameworks use_frameworks! @@ -9,12 +8,11 @@ def capacitor_pods end target 'Plugin' do - use_frameworks! capacitor_pods + pod 'AppCenterCapacitorShared', '0.3.0' pod 'AppCenter/Crashes', '4.1.1' end target 'PluginTests' do - use_frameworks! capacitor_pods end diff --git a/appcenter-crashes/src/definitions.ts b/appcenter-crashes/src/definitions.ts index 936731c..f066bea 100644 --- a/appcenter-crashes/src/definitions.ts +++ b/appcenter-crashes/src/definitions.ts @@ -72,6 +72,7 @@ export interface CrashesPlugin { isEnabled(): Promise<{value: boolean}>; /** * You can enable and disable App Center Crashes at runtime. If you disable it, the SDK won't do any crash reporting for the app. + * The state is persisted in the device's storage across application launches. * @param {shouldEnable: boolean} options * @since 0.1.0 * @example @@ -79,7 +80,7 @@ export interface CrashesPlugin { * await Crashes.enable({shouldEnable: true}); */ - setEnable(options: {shouldEnable: boolean}): Promise; + setEnabled(options: {shouldEnable: boolean}): Promise; } // convert diff --git a/appcenter-crashes/src/index.ts b/appcenter-crashes/src/index.ts index f29f395..1b11d29 100644 --- a/appcenter-crashes/src/index.ts +++ b/appcenter-crashes/src/index.ts @@ -2,12 +2,9 @@ import { registerPlugin } from '@capacitor/core'; import type { CrashesPlugin } from './definitions'; -const Crashes = registerPlugin( - 'Crashes', - { - web: () => import('./web').then(m => new m.CrashesWeb()), - }, -); +const Crashes = registerPlugin('Crashes', { + web: () => import('./web').then(m => new m.CrashesWeb()), +},); export * from './definitions'; export default Crashes; diff --git a/appcenter-crashes/src/web.ts b/appcenter-crashes/src/web.ts index 25bd8b5..a163293 100644 --- a/appcenter-crashes/src/web.ts +++ b/appcenter-crashes/src/web.ts @@ -8,7 +8,7 @@ export class CrashesWeb isEnabled(): Promise<{ value: boolean; }> { throw this.unimplemented('Not supported on web.'); } - setEnable(): Promise { + setEnabled(): Promise { throw this.unimplemented('Not supported on web.'); } } From 60312f94a7e5fa2f8eeb377c8cc2e3a901311332 Mon Sep 17 00:00:00 2001 From: John Borges Date: Thu, 10 Jun 2021 20:12:30 -0400 Subject: [PATCH 08/27] docs(crashes): fix links and function refactor --- README.md | 18 ++++++++++-------- appcenter-crashes/README.md | 9 +++++---- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 868ae4c..10bfc21 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # App Center SDK for Capacitor -> ### :rotating_light: Project is in active development and not ready to be used. Check back later. :rotating_light: +> ### :rotating_light: Project is in active development. :rotating_light: App Center is mission control for mobile apps. Get faster release cycles, higher-quality apps, and the insights to build what users want. @@ -10,9 +10,9 @@ The Capacitor App Center SDK consists of a several plugins so you can use any or | Package | Source | Version | | --- | --- | --- | -| [`@capacitor-community/appcenter`](https://capacitorjs.com/docs/v3/apis/action-sheet) | [`./appcenter`](./appcenter) | [![npm badge](https://img.shields.io/npm/v/@capacitor-community/appcenter?style=flat-square)](https://www.npmjs.com/package/@capacitor-community/appcenter) -| [`@capacitor-community/appcenter-analytics`](https://capacitorjs.com/docs/v3/apis/appcenter-analytics) | [`./appcenter-analytics`](./appcenter-analytics) | [![npm badge](https://img.shields.io/npm/v/@capacitor-community/appcenter-analytics?style=flat-square)](https://www.npmjs.com/package/@capacitor-community/appcenter-analytics) -| [`@capacitor-community/appcenter-crashes`](https://capacitorjs.com/docs/v3/apis/appcenter-crashes) | [`./appcenter-crashes`](./appcenter-crashes) | [![npm badge](https://img.shields.io/npm/v/@capacitor-community/appcenter-crashes?style=flat-square)](https://www.npmjs.com/package/@capacitor-community/appcenter-crashes) +| `@capacitor-community/appcenter` | [`./appcenter`](https://github.com/capacitor-community/appcenter-sdk-capacitor/tree/master/appcenter) | [![npm badge](https://img.shields.io/npm/v/@capacitor-community/appcenter?style=flat-square)](https://www.npmjs.com/package/@capacitor-community/appcenter) +| `@capacitor-community/appcenter-analytics` | [`./appcenter-analytics`](https://github.com/capacitor-community/appcenter-sdk-capacitor/tree/master/appcenter-analytics) | [![npm badge](https://img.shields.io/npm/v/@capacitor-community/appcenter-analytics?style=flat-square)](https://www.npmjs.com/package/@capacitor-community/appcenter-analytics) +| `@capacitor-community/appcenter-crashes` | [`./appcenter-crashes`](https://github.com/capacitor-community/appcenter-sdk-capacitor/tree/master/appcenter-crashes) | [![npm badge](https://img.shields.io/npm/v/@capacitor-community/appcenter-crashes?style=flat-square)](https://www.npmjs.com/package/@capacitor-community/appcenter-crashes) ## 📱 Example Mobile App @@ -23,12 +23,10 @@ You can get familiar with SDK quickly by cloning this repository and running the Add the App Center plugin(s) that fit your needs directly from the CLI: ```bash -npm i @capacitor-community/appcenter @capacitor-community/appcenter-analytics +npm i @capacitor-community/appcenter @capacitor-community/appcenter-analytics @capacitor-community/appcenter-crashes npx cap sync ``` -This will install two of the plugins available today. - ## 2. 🛠 Configure the SDK You must configure the project with your App Center project app secret before you can use the App Center SDK in your Capacitor project. There are other values that can also be added, but they are optional. @@ -51,9 +49,13 @@ Example: LogLevel 2 + AnalyticsEnableInJs + AnalyticsTransmissionInterval 3 - AnalyticsEnableInJs + CrashesEnableInJs + + CrashesAlwaysSend diff --git a/appcenter-crashes/README.md b/appcenter-crashes/README.md index db99453..439ca94 100644 --- a/appcenter-crashes/README.md +++ b/appcenter-crashes/README.md @@ -1,6 +1,6 @@ # @capacitor-community/appcenter-crashes -App Center Crashes records the state of the app and device and automatically generates a crash log. +App Center Crashes will automatically generate a crash log every time your app crashes. The log is first written to the device's storage and when the user starts the app again, the crash report will be sent to App Center. ## Install @@ -14,7 +14,7 @@ npx cap sync * [`isEnabled()`](#isenabled) -* [`setEnable(...)`](#setenable) +* [`setEnabled(...)`](#setenabled) @@ -36,13 +36,14 @@ Check if Crashes is enabled or not. -------------------- -### setEnable(...) +### setEnabled(...) ```typescript -setEnable(options: { shouldEnable: boolean; }) => any +setEnabled(options: { shouldEnable: boolean; }) => any ``` You can enable and disable App Center Crashes at runtime. If you disable it, the SDK won't do any crash reporting for the app. +The state is persisted in the device's storage across application launches. | Param | Type | | ------------- | --------------------------------------- | From 1b575c86b5a24de6dab79918123c025122ce605f Mon Sep 17 00:00:00 2001 From: John Borges Date: Thu, 10 Jun 2021 20:12:51 -0400 Subject: [PATCH 09/27] chore(example): include crashes plugin --- example/ios/App/Podfile | 1 + example/package.json | 1 + .../components/app-crashes/app-crashes.tsx | 56 ++++++++++++++++--- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/example/ios/App/Podfile b/example/ios/App/Podfile index 2d254b3..9b18174 100644 --- a/example/ios/App/Podfile +++ b/example/ios/App/Podfile @@ -11,6 +11,7 @@ def capacitor_pods pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCommunityAppcenter', :path => '../../../appcenter' pod 'CapacitorCommunityAppcenterAnalytics', :path => '../../../appcenter-analytics' + pod 'CapacitorCommunityAppcenterCrashes', :path => '../../../appcenter-crashes' pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app' pod 'CapacitorDevice', :path => '../../node_modules/@capacitor/device' pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics' diff --git a/example/package.json b/example/package.json index ee72385..7bdc25a 100644 --- a/example/package.json +++ b/example/package.json @@ -21,6 +21,7 @@ "dependencies": { "@capacitor-community/appcenter": "0.3.4", "@capacitor-community/appcenter-analytics": "0.2.0", + "@capacitor-community/appcenter-crashes": "^0.1.0", "@capacitor/app": "^1.0.0", "@capacitor/cli": "3.0.0", "@capacitor/core": "3.0.0", diff --git a/example/src/components/app-crashes/app-crashes.tsx b/example/src/components/app-crashes/app-crashes.tsx index 348cf71..b0b4651 100644 --- a/example/src/components/app-crashes/app-crashes.tsx +++ b/example/src/components/app-crashes/app-crashes.tsx @@ -1,18 +1,58 @@ -import { Component, Host, h } from '@stencil/core'; +import { Component, State, h } from '@stencil/core'; +import { ToggleChangeEventDetail } from '@ionic/core'; +import Crashes from '@capacitor-community/appcenter-crashes'; @Component({ tag: 'app-crashes', styleUrl: 'app-crashes.css', - shadow: true, }) export class AppCrashes { + /* Flag to toggle entire Crashes service */ + @State() enabled: boolean = false - render() { - return ( - - - - ); + constructor() { + this.toggleCrashes = this.toggleCrashes.bind(this); } + async componentWillLoad() { + try { + const { value: crashesEnabled } = await Crashes.isEnabled(); + + this.enabled = crashesEnabled + } catch (error) { + console.error(error) + } + } + + async toggleCrashes(e: CustomEvent) { + try { + await Crashes.setEnabled({shouldEnable: e.detail.checked}); + this.enabled = e.detail.checked + } catch (error) { + this.enabled = false + console.error(error) + } + } + + render() { + return [ + + + + + + Crashes + + , + + + + + Enable Analytics + this.toggleCrashes(e)} /> + + + , + ]; + } } From e800e2c35bb609799b7ec2c755b7e823d444657e Mon Sep 17 00:00:00 2001 From: John Borges Date: Fri, 11 Jun 2021 14:12:18 -0400 Subject: [PATCH 10/27] feat(crashes): add generateTestCrash function --- appcenter-crashes/README.md | 18 +++++++++++++++++- .../ios/Plugin/AppCenterCrashesBase.swift | 4 ++++ .../ios/Plugin/AppCenterCrashesPlugin.m | 1 + .../ios/Plugin/AppCenterCrashesPlugin.swift | 5 +++++ appcenter-crashes/package.json | 4 ++-- appcenter-crashes/src/definitions.ts | 14 ++++++++++++-- appcenter-crashes/src/web.ts | 3 +++ 7 files changed, 44 insertions(+), 5 deletions(-) diff --git a/appcenter-crashes/README.md b/appcenter-crashes/README.md index 439ca94..f4267a8 100644 --- a/appcenter-crashes/README.md +++ b/appcenter-crashes/README.md @@ -1,6 +1,6 @@ # @capacitor-community/appcenter-crashes -App Center Crashes will automatically generate a crash log every time your app crashes. The log is first written to the device's storage and when the user starts the app again, the crash report will be sent to App Center. +App Center Crashes will automatically generate a crash log every time your app crashes. The log is first written to the device's storage and when the user starts the app again, the crash report will be sent to App Center. Collecting crashes works for both beta and live apps, i.e. those submitted to the App Store. Crash logs contain valuable information for you to help fix the crash. ## Install @@ -15,6 +15,7 @@ npx cap sync * [`isEnabled()`](#isenabled) * [`setEnabled(...)`](#setenabled) +* [`generateTestCrash()`](#generatetestcrash) @@ -55,4 +56,19 @@ The state is persisted in the device's storage across application launches. -------------------- + +### generateTestCrash() + +```typescript +generateTestCrash() => any +``` + +Generate a test crash for easy testing of the SDK. This API can only be used in test/beta apps and won't do anything in production apps. + +**Returns:** any + +**Since:** 0.2.0 + +-------------------- + diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift index a6e1f8c..c9d3311 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift @@ -16,4 +16,8 @@ import AppCenterCrashes public func start() { AppCenter.startService(Crashes.self) } + + public func generateTestCrash() { + Crashes.generateTestCrash() + } } diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m index d33897b..013ba63 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m @@ -6,4 +6,5 @@ CAP_PLUGIN(CrashesPlugin, "Crashes", CAP_PLUGIN_METHOD(setEnabled, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(isEnabled, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(generateTestCrash, CAPPluginReturnPromise); ) diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift index a4cee83..9e63859 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift @@ -39,4 +39,9 @@ public class CrashesPlugin: CAPPlugin { call.resolve(["value": implementation.isEnabled()]) call.resolve() } + + @objc func generateTestCrash(_ call: CAPPluginCall) { + implementation.generateTestCrash() + call.resolve() + } } diff --git a/appcenter-crashes/package.json b/appcenter-crashes/package.json index 4d1eba1..2753f60 100644 --- a/appcenter-crashes/package.json +++ b/appcenter-crashes/package.json @@ -1,7 +1,7 @@ { "name": "@capacitor-community/appcenter-crashes", - "version": "0.1.0", - "description": "App Center Crashes records the state of the app and device and automatically generates a crash log.", + "version": "0.2.0", + "description": "Capacitor plugin for Microsoft AppCenter Crashes.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", "types": "dist/esm/index.d.ts", diff --git a/appcenter-crashes/src/definitions.ts b/appcenter-crashes/src/definitions.ts index f066bea..d450247 100644 --- a/appcenter-crashes/src/definitions.ts +++ b/appcenter-crashes/src/definitions.ts @@ -70,6 +70,7 @@ export interface CrashesPlugin { * const { value: enabled } = await Crashes.isEnabled(); */ isEnabled(): Promise<{value: boolean}>; + /** * You can enable and disable App Center Crashes at runtime. If you disable it, the SDK won't do any crash reporting for the app. * The state is persisted in the device's storage across application launches. @@ -77,14 +78,23 @@ export interface CrashesPlugin { * @since 0.1.0 * @example * import Crashes from '@capacitor-community/appcenter-crashes'; - + * * await Crashes.enable({shouldEnable: true}); */ setEnabled(options: {shouldEnable: boolean}): Promise; + + /** + * Generate a test crash for easy testing of the SDK. This API can only be used in test/beta apps and won't do anything in production apps. + * @since 0.2.0 + * @example + * import Crashes from '@capacitor-community/appcenter-crashes'; + * + * await Crashes.generateTestCrash(); + */ + generateTestCrash(): Promise; } // convert -// export function generateTestCrash(): Promise; // export function hasCrashedInLastSession(): Promise; // export function hasReceivedMemoryWarningInLastSession(): Promise; // export function lastSessionCrashReport(): Promise; diff --git a/appcenter-crashes/src/web.ts b/appcenter-crashes/src/web.ts index a163293..be58853 100644 --- a/appcenter-crashes/src/web.ts +++ b/appcenter-crashes/src/web.ts @@ -5,6 +5,9 @@ import type { CrashesPlugin } from './definitions'; export class CrashesWeb extends WebPlugin implements CrashesPlugin { + generateTestCrash(): Promise { + throw this.unimplemented('Not supported on web.'); + } isEnabled(): Promise<{ value: boolean; }> { throw this.unimplemented('Not supported on web.'); } From 43836e44e4c41bc3180ce7318a6ade1c8c143afd Mon Sep 17 00:00:00 2001 From: John Borges Date: Fri, 11 Jun 2021 14:13:04 -0400 Subject: [PATCH 11/27] chore(example): use generateTestCrash --- example/package.json | 2 +- example/src/components/app-crashes/app-crashes.css | 10 ++++++++++ example/src/components/app-crashes/app-crashes.tsx | 14 ++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/example/package.json b/example/package.json index 7bdc25a..ed5c2fd 100644 --- a/example/package.json +++ b/example/package.json @@ -21,7 +21,7 @@ "dependencies": { "@capacitor-community/appcenter": "0.3.4", "@capacitor-community/appcenter-analytics": "0.2.0", - "@capacitor-community/appcenter-crashes": "^0.1.0", + "@capacitor-community/appcenter-crashes": "0.2.0", "@capacitor/app": "^1.0.0", "@capacitor/cli": "3.0.0", "@capacitor/core": "3.0.0", diff --git a/example/src/components/app-crashes/app-crashes.css b/example/src/components/app-crashes/app-crashes.css index 5d4e87f..614e5a3 100644 --- a/example/src/components/app-crashes/app-crashes.css +++ b/example/src/components/app-crashes/app-crashes.css @@ -1,3 +1,13 @@ :host { display: block; } + +header { + margin-bottom: 1.25em; +} + +section { + margin-top: 1em; + margin-bottom: 2.5em; +} + diff --git a/example/src/components/app-crashes/app-crashes.tsx b/example/src/components/app-crashes/app-crashes.tsx index b0b4651..3eac9af 100644 --- a/example/src/components/app-crashes/app-crashes.tsx +++ b/example/src/components/app-crashes/app-crashes.tsx @@ -12,6 +12,7 @@ export class AppCrashes { constructor() { this.toggleCrashes = this.toggleCrashes.bind(this); + this.crashApp = this.crashApp.bind(this); } async componentWillLoad() { @@ -34,6 +35,14 @@ export class AppCrashes { } } + async crashApp() { + try { + await Crashes.generateTestCrash() + } catch (error) { + + } + } + render() { return [ @@ -52,6 +61,11 @@ export class AppCrashes { this.toggleCrashes(e)} /> +
+
+
Generate Test Crash
+ Let app crash +
, ]; } From 07b4f0ebe6102b3e8b6799326f336153820b50e3 Mon Sep 17 00:00:00 2001 From: John Borges Date: Fri, 11 Jun 2021 22:29:37 -0400 Subject: [PATCH 12/27] feat(crashes): add memory warning function --- appcenter-crashes/README.md | 16 ++++++++++++++++ .../ios/Plugin/AppCenterCrashesBase.swift | 4 ++++ .../ios/Plugin/AppCenterCrashesPlugin.m | 1 + .../ios/Plugin/AppCenterCrashesPlugin.swift | 12 ++++-------- appcenter-crashes/src/definitions.ts | 12 +++++++++++- appcenter-crashes/src/web.ts | 3 +++ .../src/components/app-crashes/app-crashes.tsx | 11 +++++++++++ 7 files changed, 50 insertions(+), 9 deletions(-) diff --git a/appcenter-crashes/README.md b/appcenter-crashes/README.md index f4267a8..3fc9179 100644 --- a/appcenter-crashes/README.md +++ b/appcenter-crashes/README.md @@ -16,6 +16,7 @@ npx cap sync * [`isEnabled()`](#isenabled) * [`setEnabled(...)`](#setenabled) * [`generateTestCrash()`](#generatetestcrash) +* [`hasReceivedMemoryWarningInLastSession()`](#hasreceivedmemorywarninginlastsession) @@ -71,4 +72,19 @@ Generate a test crash for easy testing of the SDK. This API can only be used in -------------------- + +### hasReceivedMemoryWarningInLastSession() + +```typescript +hasReceivedMemoryWarningInLastSession() => any +``` + +Check if app recieved memory warning in the last session. + +**Returns:** any + +**Since:** 0.2.0 + +-------------------- + diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift index c9d3311..634d426 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift @@ -20,4 +20,8 @@ import AppCenterCrashes public func generateTestCrash() { Crashes.generateTestCrash() } + + public func hasReceivedMemoryWarningInLastSession() -> Bool { + return Crashes.hasReceivedMemoryWarningInLastSession + } } diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m index 013ba63..a6d75c6 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m @@ -7,4 +7,5 @@ CAP_PLUGIN_METHOD(setEnabled, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(isEnabled, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(generateTestCrash, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(hasReceivedMemoryWarningInLastSession, CAPPluginReturnPromise); ) diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift index 9e63859..c7a57b0 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift @@ -16,17 +16,10 @@ public class CrashesPlugin: CAPPlugin { let config: NSDictionary = AppCenterCapacitorShared.getConfiguration() // get Crashes config options - let enableInJs = config["CrashesEnableInJs"] as? Bool let alwaysSendCrashes = config["CrashesAlwaysSend"] as? Bool if AppCenterCapacitorShared.isSdkConfigured() { - implementation.start() - - // disable auto start of Crashes - if enableInJs ?? false { - implementation.enable(false) - } } } @@ -37,11 +30,14 @@ public class CrashesPlugin: CAPPlugin { @objc func isEnabled(_ call: CAPPluginCall) { call.resolve(["value": implementation.isEnabled()]) - call.resolve() } @objc func generateTestCrash(_ call: CAPPluginCall) { implementation.generateTestCrash() call.resolve() } + + @objc func hasReceivedMemoryWarningInLastSession(_ call: CAPPluginCall) { + call.resolve(["value": implementation.hasReceivedMemoryWarningInLastSession()]) + } } diff --git a/appcenter-crashes/src/definitions.ts b/appcenter-crashes/src/definitions.ts index d450247..6272369 100644 --- a/appcenter-crashes/src/definitions.ts +++ b/appcenter-crashes/src/definitions.ts @@ -92,11 +92,21 @@ export interface CrashesPlugin { * await Crashes.generateTestCrash(); */ generateTestCrash(): Promise; + + /** + * Check if app recieved memory warning in the last session. + * @returns {Promise<{value: boolean}>} + * @since 0.2.0 + * @example + * import Crashes from '@capacitor-community/appcenter-crashes'; + * + * const { value: gotMemWarning } = await Crashes.hasReceivedMemoryWarningInLastSession(); + */ + hasReceivedMemoryWarningInLastSession(): Promise<{value: boolean}>; } // convert // export function hasCrashedInLastSession(): Promise; -// export function hasReceivedMemoryWarningInLastSession(): Promise; // export function lastSessionCrashReport(): Promise; // export function notifyUserConfirmation(userConfirmation: UserConfirmation): void; // export function setListener(crashesListener: CrashesListener): Promise; diff --git a/appcenter-crashes/src/web.ts b/appcenter-crashes/src/web.ts index be58853..e810c76 100644 --- a/appcenter-crashes/src/web.ts +++ b/appcenter-crashes/src/web.ts @@ -5,6 +5,9 @@ import type { CrashesPlugin } from './definitions'; export class CrashesWeb extends WebPlugin implements CrashesPlugin { + hasReceivedMemoryWarningInLastSession(): Promise<{ value: boolean; }> { + throw this.unimplemented('Not supported on web.'); + } generateTestCrash(): Promise { throw this.unimplemented('Not supported on web.'); } diff --git a/example/src/components/app-crashes/app-crashes.tsx b/example/src/components/app-crashes/app-crashes.tsx index 3eac9af..206d87f 100644 --- a/example/src/components/app-crashes/app-crashes.tsx +++ b/example/src/components/app-crashes/app-crashes.tsx @@ -9,6 +9,7 @@ import Crashes from '@capacitor-community/appcenter-crashes'; export class AppCrashes { /* Flag to toggle entire Crashes service */ @State() enabled: boolean = false + @State() memoryWarning: boolean = false constructor() { this.toggleCrashes = this.toggleCrashes.bind(this); @@ -18,8 +19,11 @@ export class AppCrashes { async componentWillLoad() { try { const { value: crashesEnabled } = await Crashes.isEnabled(); + const { value: memoryWarning } = await Crashes.hasReceivedMemoryWarningInLastSession(); this.enabled = crashesEnabled + this.memoryWarning = memoryWarning + console.debug(`got mem warning: ${this.memoryWarning}`) } catch (error) { console.error(error) } @@ -60,6 +64,13 @@ export class AppCrashes { Enable Analytics this.toggleCrashes(e)} /> + + Previous Crash Info + + + Memory Warning + {this.memoryWarning.toString()} +
From be2f69ae95e7b4a4710e3feb46c3d4dfb4ad147f Mon Sep 17 00:00:00 2001 From: John Borges Date: Sat, 12 Jun 2021 10:24:02 -0400 Subject: [PATCH 13/27] feat(crashes): add hasCrashedInLastSession --- appcenter-crashes/CHANGELOG.md | 5 +++++ .../ios/Plugin/AppCenterCrashesBase.swift | 4 ++++ .../ios/Plugin/AppCenterCrashesPlugin.m | 1 + .../ios/Plugin/AppCenterCrashesPlugin.swift | 5 +++++ appcenter-crashes/package.json | 2 +- appcenter-crashes/src/definitions.ts | 12 +++++++++++- appcenter-crashes/src/web.ts | 3 +++ example/src/components/app-crashes/app-crashes.tsx | 8 +++++++- 8 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 appcenter-crashes/CHANGELOG.md diff --git a/appcenter-crashes/CHANGELOG.md b/appcenter-crashes/CHANGELOG.md new file mode 100644 index 0000000..75e2a81 --- /dev/null +++ b/appcenter-crashes/CHANGELOG.md @@ -0,0 +1,5 @@ +# Change Log + +## Features + +* Add hasCrashedInLastSession api diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift index 634d426..dd649da 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift @@ -24,4 +24,8 @@ import AppCenterCrashes public func hasReceivedMemoryWarningInLastSession() -> Bool { return Crashes.hasReceivedMemoryWarningInLastSession } + + public func hasCrashedInLastSession() -> Bool { + return Crashes.hasCrashedInLastSession + } } diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m index a6d75c6..1f7d2b2 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m @@ -8,4 +8,5 @@ CAP_PLUGIN_METHOD(isEnabled, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(generateTestCrash, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(hasReceivedMemoryWarningInLastSession, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(hasCrashedInLastSession, CAPPluginReturnPromise); ) diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift index c7a57b0..aebf9f8 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift @@ -40,4 +40,9 @@ public class CrashesPlugin: CAPPlugin { @objc func hasReceivedMemoryWarningInLastSession(_ call: CAPPluginCall) { call.resolve(["value": implementation.hasReceivedMemoryWarningInLastSession()]) } + + @objc func hasCrashedInLastSession(_ call: CAPPluginCall) { + call.resolve(["value": implementation.hasCrashedInLastSession()]) + } + } diff --git a/appcenter-crashes/package.json b/appcenter-crashes/package.json index 2753f60..90f2154 100644 --- a/appcenter-crashes/package.json +++ b/appcenter-crashes/package.json @@ -1,6 +1,6 @@ { "name": "@capacitor-community/appcenter-crashes", - "version": "0.2.0", + "version": "0.3.0", "description": "Capacitor plugin for Microsoft AppCenter Crashes.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", diff --git a/appcenter-crashes/src/definitions.ts b/appcenter-crashes/src/definitions.ts index 6272369..c432378 100644 --- a/appcenter-crashes/src/definitions.ts +++ b/appcenter-crashes/src/definitions.ts @@ -103,10 +103,20 @@ export interface CrashesPlugin { * const { value: gotMemWarning } = await Crashes.hasReceivedMemoryWarningInLastSession(); */ hasReceivedMemoryWarningInLastSession(): Promise<{value: boolean}>; + + /** + * Check if the app has crashed in the last session. + * @returns {Promise<{value: boolean}>} + * @since 0.3.0 + * @example + * import Crashes from '@capacitor-community/appcenter-crashes'; + * + * const { value: hasCrashed } = await Crashes.hasCrashedInLastSession(); + */ + hasCrashedInLastSession(): Promise<{ value: boolean}>; } // convert -// export function hasCrashedInLastSession(): Promise; // export function lastSessionCrashReport(): Promise; // export function notifyUserConfirmation(userConfirmation: UserConfirmation): void; // export function setListener(crashesListener: CrashesListener): Promise; diff --git a/appcenter-crashes/src/web.ts b/appcenter-crashes/src/web.ts index e810c76..aa2348b 100644 --- a/appcenter-crashes/src/web.ts +++ b/appcenter-crashes/src/web.ts @@ -5,6 +5,9 @@ import type { CrashesPlugin } from './definitions'; export class CrashesWeb extends WebPlugin implements CrashesPlugin { + hasCrashedInLastSession(): Promise<{ value: boolean; }> { + throw this.unimplemented('Not supported on web.'); + } hasReceivedMemoryWarningInLastSession(): Promise<{ value: boolean; }> { throw this.unimplemented('Not supported on web.'); } diff --git a/example/src/components/app-crashes/app-crashes.tsx b/example/src/components/app-crashes/app-crashes.tsx index 206d87f..0211d75 100644 --- a/example/src/components/app-crashes/app-crashes.tsx +++ b/example/src/components/app-crashes/app-crashes.tsx @@ -10,6 +10,7 @@ export class AppCrashes { /* Flag to toggle entire Crashes service */ @State() enabled: boolean = false @State() memoryWarning: boolean = false + @State() hasCrashed: boolean = false constructor() { this.toggleCrashes = this.toggleCrashes.bind(this); @@ -20,10 +21,11 @@ export class AppCrashes { try { const { value: crashesEnabled } = await Crashes.isEnabled(); const { value: memoryWarning } = await Crashes.hasReceivedMemoryWarningInLastSession(); + const { value: hasCrashed } = await Crashes.hasCrashedInLastSession(); this.enabled = crashesEnabled this.memoryWarning = memoryWarning - console.debug(`got mem warning: ${this.memoryWarning}`) + this.hasCrashed = hasCrashed } catch (error) { console.error(error) } @@ -71,6 +73,10 @@ export class AppCrashes { Memory Warning {this.memoryWarning.toString()} + + Crashed Before + {this.hasCrashed.toString()} +
From d7254dbd88129366fb57bef6da7d8b1ca704f5db Mon Sep 17 00:00:00 2001 From: John Borges Date: Mon, 14 Jun 2021 21:42:09 -0400 Subject: [PATCH 14/27] feat(crashes): add lastSessionCrashReport --- appcenter-crashes/CHANGELOG.md | 1 + appcenter-crashes/README.md | 73 +++++++++++++++++++ .../ios/Plugin/AppCenterCrashesBase.swift | 4 + .../ios/Plugin/AppCenterCrashesPlugin.m | 2 + .../ios/Plugin/AppCenterCrashesPlugin.swift | 11 +++ appcenter-crashes/src/definitions.ts | 52 ++++++++++--- appcenter-crashes/src/web.ts | 5 +- 7 files changed, 138 insertions(+), 10 deletions(-) diff --git a/appcenter-crashes/CHANGELOG.md b/appcenter-crashes/CHANGELOG.md index 75e2a81..e5378a1 100644 --- a/appcenter-crashes/CHANGELOG.md +++ b/appcenter-crashes/CHANGELOG.md @@ -3,3 +3,4 @@ ## Features * Add hasCrashedInLastSession api +* Add lastSessionCrashReport api diff --git a/appcenter-crashes/README.md b/appcenter-crashes/README.md index 3fc9179..441bb96 100644 --- a/appcenter-crashes/README.md +++ b/appcenter-crashes/README.md @@ -17,6 +17,9 @@ npx cap sync * [`setEnabled(...)`](#setenabled) * [`generateTestCrash()`](#generatetestcrash) * [`hasReceivedMemoryWarningInLastSession()`](#hasreceivedmemorywarninginlastsession) +* [`hasCrashedInLastSession()`](#hascrashedinlastsession) +* [`lastSessionCrashReport()`](#lastsessioncrashreport) +* [Interfaces](#interfaces) @@ -87,4 +90,74 @@ Check if app recieved memory warning in the last session. -------------------- + +### hasCrashedInLastSession() + +```typescript +hasCrashedInLastSession() => any +``` + +Check if the app has crashed in the last session. + +**Returns:** any + +**Since:** 0.3.0 + +-------------------- + + +### lastSessionCrashReport() + +```typescript +lastSessionCrashReport() => any +``` + +Provides details about the crash that occurred in the last app session. + +**Returns:** any + +**Since:** 0.3.0 + +-------------------- + + +### Interfaces + + +#### ErrorReport + +| Prop | Type | +| -------------------------- | ----------------------------------------- | +| **`id`** | string | +| **`threadName`** | string | +| **`appErrorTime`** | string \| number | +| **`appStartTime`** | string \| number | +| **`exceptionName`** | string | +| **`exceptionReason`** | string | +| **`device`** | Device | +| **`signal`** | string | +| **`appProcessIdentifier`** | number | + + +#### Device + +| Prop | Type | +| -------------------- | ------------------- | +| **`sdkName`** | string | +| **`sdkVersion`** | string | +| **`model`** | string | +| **`oemName`** | string | +| **`osName`** | string | +| **`osVersion`** | string | +| **`osBuild`** | string | +| **`osApiLevel`** | number | +| **`locale`** | string | +| **`timeZoneOffset`** | number | +| **`screenSize`** | string | +| **`appVersion`** | string | +| **`carrierName`** | string | +| **`carrierCountry`** | string | +| **`appBuild`** | string | +| **`appNamespace`** | string | + diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift index dd649da..6b87df4 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesBase.swift @@ -28,4 +28,8 @@ import AppCenterCrashes public func hasCrashedInLastSession() -> Bool { return Crashes.hasCrashedInLastSession } + + public func lastSessionCrashReport() -> Dictionary? { + return CrashesUtil.convertReportToJs(report: Crashes.lastSessionCrashReport) + } } diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m index 1f7d2b2..8d5d3d6 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m @@ -9,4 +9,6 @@ CAP_PLUGIN_METHOD(generateTestCrash, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(hasReceivedMemoryWarningInLastSession, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(hasCrashedInLastSession, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(lastSessionCrashReport, CAPPluginReturnPromise); + ) diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift index aebf9f8..879132e 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift @@ -19,6 +19,7 @@ public class CrashesPlugin: CAPPlugin { let alwaysSendCrashes = config["CrashesAlwaysSend"] as? Bool if AppCenterCapacitorShared.isSdkConfigured() { + print("[CrashesPlugin] starting") implementation.start() } } @@ -44,5 +45,15 @@ public class CrashesPlugin: CAPPlugin { @objc func hasCrashedInLastSession(_ call: CAPPluginCall) { call.resolve(["value": implementation.hasCrashedInLastSession()]) } + + @objc func lastSessionCrashReport(_ call: CAPPluginCall) { + + guard let report = implementation.lastSessionCrashReport() else { + call.reject("No crash report available") + return + } + + call.resolve(["value": report]) + } } diff --git a/appcenter-crashes/src/definitions.ts b/appcenter-crashes/src/definitions.ts index c432378..d4b064e 100644 --- a/appcenter-crashes/src/definitions.ts +++ b/appcenter-crashes/src/definitions.ts @@ -5,34 +5,58 @@ export enum UserConfirmation { } export interface Device { + /* Name of the SDK. Consists of the name of the SDK and the platform, e.g. "appcenter.ios", "appcenter.android" */ sdkName: string; + /* Version of the SDK in semver format, e.g. "1.2.0" or "0.12.3-alpha.1". */ sdkVersion: string; + /* Device model (example: iPad2,3). */ model: string; + /* Device manufacturer (example: HTC). */ oemName: string; + /* OS name (example: iOS). */ osName: string; + /* OS version (example: 9.3.0). */ osVersion: string; - osBuild: string; + /* OS build code (example: LMY47X). */ + osBuild?: string; + /* API level when applicable like in Android (example: 15). */ osApiLevel?: number; + /* Language code (example: en_US). */ locale: string; + /* The offset in minutes from UTC for the device time zone, including daylight savings time. */ timeZoneOffset: number; - screenSize?: string; + /* Screen size of the device in pixels (example: 640x480). */ + screenSize: string; + /* Application version name, e.g. 1.1.0 */ appVersion: string; + /* Carrier name (for mobile devices). */ carrierName?: string; + /* Carrier country code (for mobile devices). */ carrierCountry?: string; + /* The app's build number, e.g. 42. */ appBuild: string; - appNamespace: string; + /* The bundle identifier, package identifier, or namespace, depending on what the individual plattforms use, .e.g com.microsoft.example. */ + appNamespace?: string; } export interface ErrorReport { + /* UUID for the crash report. */ id: string; threadName?: string; - appErrorTime: string | number; - appStartTime: string | number; - exception?: string; + /* Date and time the error occurred. */ + appErrorTime?: string | number; + /* Date and time the app started. */ + appStartTime?: string | number; + /* Exception name that triggered the crash. */ + exceptionName?: string; + /* Exception reason. */ exceptionReason?: string; + /* Device information of the app when it crashed. */ device: Device; - signal?: string; - appProcessIdentifier?: number; + /* Signal that caused the crash. */ + signal: string; + /* Identifier of the app process that crashed. */ + appProcessIdentifier: number; } export interface CrashesListener { @@ -114,9 +138,19 @@ export interface CrashesPlugin { * const { value: hasCrashed } = await Crashes.hasCrashedInLastSession(); */ hasCrashedInLastSession(): Promise<{ value: boolean}>; + + /** + * Provides details about the crash that occurred in the last app session. + * @returns {Promise<{value: ErrorReport}>} + * @since 0.3.0 + * @example + * import Crashes from '@capacitor-community/appcenter-crashes'; + * + * const { value: crashReport } = await Crashes.lastSessionCrashReport(); + */ + lastSessionCrashReport(): Promise<{value: ErrorReport}>; } // convert -// export function lastSessionCrashReport(): Promise; // export function notifyUserConfirmation(userConfirmation: UserConfirmation): void; // export function setListener(crashesListener: CrashesListener): Promise; diff --git a/appcenter-crashes/src/web.ts b/appcenter-crashes/src/web.ts index aa2348b..ed0cce5 100644 --- a/appcenter-crashes/src/web.ts +++ b/appcenter-crashes/src/web.ts @@ -1,10 +1,13 @@ import { WebPlugin } from '@capacitor/core'; -import type { CrashesPlugin } from './definitions'; +import { CrashesPlugin, ErrorReport } from './definitions'; export class CrashesWeb extends WebPlugin implements CrashesPlugin { + lastSessionCrashReport(): Promise<{ value: ErrorReport; }> { + throw new Error('Method not implemented.'); + } hasCrashedInLastSession(): Promise<{ value: boolean; }> { throw this.unimplemented('Not supported on web.'); } From a7cd59fb7290b7309d07a71cbdeb1a38b095672e Mon Sep 17 00:00:00 2001 From: John Borges Date: Mon, 14 Jun 2021 21:43:03 -0400 Subject: [PATCH 15/27] refactor(crashes): checking optionals --- .../ios/Plugin/AppCenterCrashesUtil.swift | 198 ++++++++---------- 1 file changed, 82 insertions(+), 116 deletions(-) diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesUtil.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesUtil.swift index 7f8bee7..e0e49db 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesUtil.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesUtil.swift @@ -2,142 +2,108 @@ import Foundation import AppCenterCrashes /** - Utility class containing helpers for converting App Center objects. + Utility class containing helpers for converting App Center objects. */ public class CrashesUtil { - static let kMSSdkName: String = "sdkName"; - static let kMSSdkVersion: String = "sdkVersion"; - static let kMSModel: String = "model"; - static let kMSOemName: String = "oemName"; - static let kMSOsName: String = "osName"; - static let kMSOsVersion: String = "osVersion"; - static let kMSOsBuild: String = "osBuild"; - static let kMSOsApiLevel: String = "osApiLevel"; - static let kMSLocale: String = "locale"; - static let kMSTimeZoneOffset: String = "timeZoneOffset"; - static let kMSScreenSize: String = "screenSize"; - static let kMSAppVersion: String = "appVersion"; - static let kMSCarrierName: String = "carrierName"; - static let kMSCarrierCountry: String = "carrierCountry"; - static let kMSAppBuild: String = "appBuild"; - static let kMSAppNamespace: String = "appNamespace"; + static let kMSSdkName: String = "sdkName"; + static let kMSSdkVersion: String = "sdkVersion"; + static let kMSModel: String = "model"; + static let kMSOemName: String = "oemName"; + static let kMSOsName: String = "osName"; + static let kMSOsVersion: String = "osVersion"; + static let kMSOsBuild: String = "osBuild"; + static let kMSOsApiLevel: String = "osApiLevel"; + static let kMSLocale: String = "locale"; + static let kMSTimeZoneOffset: String = "timeZoneOffset"; + static let kMSScreenSize: String = "screenSize"; + static let kMSAppVersion: String = "appVersion"; + static let kMSCarrierName: String = "carrierName"; + static let kMSCarrierCountry: String = "carrierCountry"; + static let kMSAppBuild: String = "appBuild"; + static let kMSAppNamespace: String = "appNamespace"; - /** - Serializes App Center Device properties to Dictionary - - Parameter device: App Center Device - - Returns Device Dictionary + /** + Serializes App Center Device properties to Dictionary + - Parameter device: App Center Device + - Returns Device Dictionary */ - public func serializeDeviceToDictionary(device: Device) -> Dictionary { - var dict = [String: Any]() + public static func serializeDeviceToDictionary(device: Device) -> Dictionary { + var dict = [String: Any]() - if !device.sdkName.isEmpty { - dict[CrashesUtil.kMSSdkName] = device.sdkName; - } - if !device.sdkName.isEmpty { - dict[CrashesUtil.kMSSdkVersion] = device.sdkVersion; - } - if !device.model.isEmpty { - dict[CrashesUtil.kMSModel] = device.model; - } - if !device.oemName.isEmpty { - dict[CrashesUtil.kMSOemName] = device.oemName; - } - if !device.osName.isEmpty { - dict[CrashesUtil.kMSOsName] = device.osName; - } - if !device.osVersion.isEmpty { - dict[CrashesUtil.kMSOsVersion] = device.osVersion; - } - if !device.osBuild.isEmpty { - dict[CrashesUtil.kMSOsBuild] = device.osBuild; - } - if device.osApiLevel != nil { - dict[CrashesUtil.kMSOsApiLevel] = device.osApiLevel!; - } - if !device.locale.isEmpty { - dict[CrashesUtil.kMSLocale] = device.locale; - } - if device.timeZoneOffset != nil { - dict[CrashesUtil.kMSTimeZoneOffset] = device.timeZoneOffset!; - } - if !device.screenSize.isEmpty { - dict[CrashesUtil.kMSScreenSize] = device.screenSize; - } - if !device.appVersion.isEmpty { - dict[CrashesUtil.kMSAppVersion] = device.appVersion; - } - if !device.carrierName.isEmpty { - dict[CrashesUtil.kMSCarrierName] = device.carrierName; - } - if !device.carrierCountry.isEmpty { - dict[CrashesUtil.kMSCarrierCountry] = device.carrierCountry; - } - if !device.appBuild.isEmpty { - dict[CrashesUtil.kMSAppBuild] = device.appBuild; - } - if !device.appNamespace.isEmpty { - dict[CrashesUtil.kMSAppNamespace] = device.appNamespace; - } - return dict; - } + dict[CrashesUtil.kMSSdkName] = device.sdkName; + dict[CrashesUtil.kMSSdkVersion] = device.sdkVersion; + dict[CrashesUtil.kMSModel] = device.model; + dict[CrashesUtil.kMSOemName] = device.oemName; + dict[CrashesUtil.kMSOsName] = device.osName; + dict[CrashesUtil.kMSOsVersion] = device.osVersion; + + if device.osBuild != nil { + dict[CrashesUtil.kMSOsBuild] = device.osBuild!; + } + if device.osApiLevel != nil { + dict[CrashesUtil.kMSOsApiLevel] = device.osApiLevel!; + } + + dict[CrashesUtil.kMSLocale] = device.locale; + dict[CrashesUtil.kMSTimeZoneOffset] = device.timeZoneOffset; + dict[CrashesUtil.kMSScreenSize] = device.screenSize; + dict[CrashesUtil.kMSAppVersion] = device.appVersion; + + if device.carrierName != nil { + dict[CrashesUtil.kMSCarrierName] = device.carrierName!; + } + if device.carrierCountry != nil { + dict[CrashesUtil.kMSCarrierCountry] = device.carrierCountry!; + } + + dict[CrashesUtil.kMSAppBuild] = device.appBuild; + + if device.appNamespace != nil { + dict[CrashesUtil.kMSAppNamespace] = device.appNamespace!; + } + + return dict; + } /** Converts App Center ErrorReport to Dictionary - Parameter report: App Center ErrorReport - Returns JS optional Dictionary */ - public func convertReportToJs(report: ErrorReport?) -> Dictionary? { + public static func convertReportToJs(report: ErrorReport?) -> Dictionary? { - guard let actualReport = report else { - return nil - } + guard let actualReport = report else { + return nil + } - var dict = [String: Any]() - - let identifier: String = actualReport.incidentIdentifier - if !identifier.isEmpty { - dict["id"] = identifier - } - - let processIdentifier: UInt = actualReport.appProcessIdentifier - dict["appProcessIdentifier"] = String(processIdentifier) - - let startTime: Date? = actualReport.appStartTime - if startTime != nil { - dict["appStartTime"] = String(startTime!.timeIntervalSince1970) - } - - let errTime: Date? = actualReport.appErrorTime - if errTime != nil { - dict["appErrorTime"] = errTime!.timeIntervalSince1970 - } - - let exceptionName: String = actualReport.exceptionName - if !exceptionName.isEmpty { - dict["exceptionName"] = exceptionName - } - - let exceptionReason: String = actualReport.exceptionReason - if !exceptionReason.isEmpty { - dict["exceptionReason"] = exceptionReason - } - - let signal: String = actualReport.signal - if !signal.isEmpty { - dict["signal"] = signal - } - - dict["device"] = serializeDeviceToDictionary(device: actualReport.device) + var dict = [String: Any]() - return dict + dict["id"] = actualReport.incidentIdentifier + dict["signal"] = actualReport.signal + if let exceptionName = actualReport.exceptionName { + dict["exceptionName"] = exceptionName + } + if let exceptionReason = actualReport.exceptionReason { + dict["exceptionReason"] = exceptionReason + } + if let startTime = actualReport.appStartTime { + dict["appStartTime"] = String(startTime.timeIntervalSince1970) + } + if let errTime = actualReport.appErrorTime { + dict["appErrorTime"] = String(errTime.timeIntervalSince1970) + } + dict["device"] = serializeDeviceToDictionary(device: actualReport.device) + dict["appProcessIdentifier"] = actualReport.appProcessIdentifier + + return dict } /** - Converts arrat of App Center ErrorReports to a Dictionary + Converts array of App Center ErrorReports to a Dictionary - Parameter reports: App Center ErrorReport - Returns Array of Dictionaries */ - public func convertReportsToJS (reports: [ErrorReport]) -> [[String: Any]] { + public static func convertReportsToJS (reports: [ErrorReport]) -> [[String: Any]] { var jsReadyReports = [[String: Any]]() for (index, value) in reports.enumerated() { guard let convertedReport = convertReportToJs(report: value) else { From ea21cabea2f7cd7e11525ebcf066c6332b9682f8 Mon Sep 17 00:00:00 2001 From: John Borges Date: Mon, 14 Jun 2021 21:43:12 -0400 Subject: [PATCH 16/27] docs: cleanup --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 10bfc21..0d66b18 100644 --- a/README.md +++ b/README.md @@ -43,21 +43,21 @@ Example: - + AppSecret {APP_SECRET_VALUE} LogLevel - 2 - AnalyticsEnableInJs - + 2 + AnalyticsEnableInJs + AnalyticsTransmissionInterval - 3 + 3 CrashesEnableInJs - + CrashesAlwaysSend - - + + ``` From 17896661cbaffcfcb1d3b7a31033dc1a5d90017b Mon Sep 17 00:00:00 2001 From: John Borges Date: Mon, 14 Jun 2021 21:43:31 -0400 Subject: [PATCH 17/27] chore(example): using latest plugins --- example/ios/App/App/AppCenter-Config.plist | 2 +- .../components/app-crashes/app-crashes.tsx | 33 ++++++++++++++----- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/example/ios/App/App/AppCenter-Config.plist b/example/ios/App/App/AppCenter-Config.plist index 236aaa8..e6f5a4f 100644 --- a/example/ios/App/App/AppCenter-Config.plist +++ b/example/ios/App/App/AppCenter-Config.plist @@ -5,7 +5,7 @@ AnalyticsTransmissionInterval 10 AnalyticsEnableInJs - + AppSecret fb3a28d5-1ed9-401c-b06a-0379f66c8650 LogLevel diff --git a/example/src/components/app-crashes/app-crashes.tsx b/example/src/components/app-crashes/app-crashes.tsx index 0211d75..f0d835b 100644 --- a/example/src/components/app-crashes/app-crashes.tsx +++ b/example/src/components/app-crashes/app-crashes.tsx @@ -1,6 +1,6 @@ import { Component, State, h } from '@stencil/core'; import { ToggleChangeEventDetail } from '@ionic/core'; -import Crashes from '@capacitor-community/appcenter-crashes'; +import Crashes, { ErrorReport } from '@capacitor-community/appcenter-crashes'; @Component({ tag: 'app-crashes', @@ -11,6 +11,7 @@ export class AppCrashes { @State() enabled: boolean = false @State() memoryWarning: boolean = false @State() hasCrashed: boolean = false + crashReport: ErrorReport constructor() { this.toggleCrashes = this.toggleCrashes.bind(this); @@ -22,10 +23,13 @@ export class AppCrashes { const { value: crashesEnabled } = await Crashes.isEnabled(); const { value: memoryWarning } = await Crashes.hasReceivedMemoryWarningInLastSession(); const { value: hasCrashed } = await Crashes.hasCrashedInLastSession(); + const { value: crashReport } = await Crashes.lastSessionCrashReport(); this.enabled = crashesEnabled this.memoryWarning = memoryWarning this.hasCrashed = hasCrashed + console.debug(crashReport) + } catch (error) { console.error(error) } @@ -56,19 +60,18 @@ export class AppCrashes { - Crashes , +

App Center Crashes

+

App Center Crashes will automatically generate a crash log every time your app crashes.

+ - Enable Analytics + Enable Crashes this.toggleCrashes(e)} /> - - Previous Crash Info - Memory Warning {this.memoryWarning.toString()} @@ -78,11 +81,25 @@ export class AppCrashes { {this.hasCrashed.toString()} -
+
-
Generate Test Crash
+
Generate a Test Crash
Let app crash
+ + + + Crash Report + + + { this.crashReport ? Object.keys(this.crashReport).map(key => { + + {key} + + }) : null} + + +
, ]; } From 477eb22f45ce1df9cc47563069ad1d3f18fdc014 Mon Sep 17 00:00:00 2001 From: John Borges Date: Tue, 15 Jun 2021 18:17:17 -0400 Subject: [PATCH 18/27] chore(crashes): add missing licence file --- appcenter-crashes/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 appcenter-crashes/LICENSE diff --git a/appcenter-crashes/LICENSE b/appcenter-crashes/LICENSE new file mode 100644 index 0000000..9c5a1fa --- /dev/null +++ b/appcenter-crashes/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) COPYRIGHT_YEAR COPYRIGHT_HOLDER + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file From 9aebeab965d3129aea0e385d20e973c51a1137e1 Mon Sep 17 00:00:00 2001 From: John Borges Date: Tue, 15 Jun 2021 18:20:01 -0400 Subject: [PATCH 19/27] docs(crashes): fix broken links and missing info --- appcenter-crashes/README.md | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/appcenter-crashes/README.md b/appcenter-crashes/README.md index 441bb96..cc5e34e 100644 --- a/appcenter-crashes/README.md +++ b/appcenter-crashes/README.md @@ -1,6 +1,35 @@ -# @capacitor-community/appcenter-crashes - -App Center Crashes will automatically generate a crash log every time your app crashes. The log is first written to the device's storage and when the user starts the app again, the crash report will be sent to App Center. Collecting crashes works for both beta and live apps, i.e. those submitted to the App Store. Crash logs contain valuable information for you to help fix the crash. +


+ +

App Center Crashes

+

@capacitor-community/appcenter-crashes

+

+ App Center Crashes will automatically generate a crash log every time your app crashes. The log is first written to the device's storage and when the user starts the app again, the crash report will be sent to App Center. Collecting crashes works for both beta and live apps, i.e. those submitted to the App Store. Crash logs contain valuable information for you to help fix the crash. +

+ +

+ + + +
+ + + + + +

+ +## Maintainers + +| Maintainer | GitHub | Social | +| -----------| -------| -------| +| John Borges | [johnborges](https://github.com/johnborges) | [@johnborges](https://twitter.com/johnborges) | + +## Features + +- Generate test crashes +- Get more information about a previous crash +- Customize how crashes are processed +- Enable or disable App Center Crashes at runtime ## Install From a6f63ecda3b28f8da76ab38ed3c6c8bc6da56bde Mon Sep 17 00:00:00 2001 From: John Borges Date: Tue, 15 Jun 2021 18:21:11 -0400 Subject: [PATCH 20/27] fix(crashes): use void return method type --- appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m index 8d5d3d6..afdc5dd 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.m @@ -6,7 +6,7 @@ CAP_PLUGIN(CrashesPlugin, "Crashes", CAP_PLUGIN_METHOD(setEnabled, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(isEnabled, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(generateTestCrash, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(generateTestCrash, CAPPluginReturnNone); CAP_PLUGIN_METHOD(hasReceivedMemoryWarningInLastSession, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(hasCrashedInLastSession, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(lastSessionCrashReport, CAPPluginReturnPromise); From aeb681798cd99d2551b9a932ac0b8a4f795c84b4 Mon Sep 17 00:00:00 2001 From: John Borges Date: Tue, 15 Jun 2021 18:21:56 -0400 Subject: [PATCH 21/27] refactor(crashes): use DispatchQueue --- .../ios/Plugin/AppCenterCrashesPlugin.swift | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift index 879132e..1ee60c0 100644 --- a/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift +++ b/appcenter-crashes/ios/Plugin/AppCenterCrashesPlugin.swift @@ -39,21 +39,26 @@ public class CrashesPlugin: CAPPlugin { } @objc func hasReceivedMemoryWarningInLastSession(_ call: CAPPluginCall) { - call.resolve(["value": implementation.hasReceivedMemoryWarningInLastSession()]) + DispatchQueue.main.async { + call.resolve(["value": self.implementation.hasReceivedMemoryWarningInLastSession()]) + } } @objc func hasCrashedInLastSession(_ call: CAPPluginCall) { - call.resolve(["value": implementation.hasCrashedInLastSession()]) + DispatchQueue.main.async { + call.resolve(["value": self.implementation.hasCrashedInLastSession()]) + } } @objc func lastSessionCrashReport(_ call: CAPPluginCall) { - - guard let report = implementation.lastSessionCrashReport() else { - call.reject("No crash report available") - return + DispatchQueue.main.async { + guard let report = self.implementation.lastSessionCrashReport() else { + call.reject("No crash report available") + return + } + + call.resolve(["value": report]) } - - call.resolve(["value": report]) } } From 774f7918ff89b6c0b7ba77117b57f8e046f89861 Mon Sep 17 00:00:00 2001 From: John Borges Date: Tue, 15 Jun 2021 18:22:14 -0400 Subject: [PATCH 22/27] chore(example): cleanup --- example/src/components/app-crashes/app-crashes.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/src/components/app-crashes/app-crashes.tsx b/example/src/components/app-crashes/app-crashes.tsx index f0d835b..0ff5608 100644 --- a/example/src/components/app-crashes/app-crashes.tsx +++ b/example/src/components/app-crashes/app-crashes.tsx @@ -11,7 +11,7 @@ export class AppCrashes { @State() enabled: boolean = false @State() memoryWarning: boolean = false @State() hasCrashed: boolean = false - crashReport: ErrorReport + @State() crashReport: ErrorReport constructor() { this.toggleCrashes = this.toggleCrashes.bind(this); @@ -77,7 +77,7 @@ export class AppCrashes { {this.memoryWarning.toString()} - Crashed Before + Crashed Prior {this.hasCrashed.toString()} From d1cf295ff9704afa623f66b9f24aac33dc482d6f Mon Sep 17 00:00:00 2001 From: John Borges Date: Tue, 15 Jun 2021 20:39:14 -0400 Subject: [PATCH 23/27] chore(crashes): updating changelog --- appcenter-crashes/CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/appcenter-crashes/CHANGELOG.md b/appcenter-crashes/CHANGELOG.md index e5378a1..326b499 100644 --- a/appcenter-crashes/CHANGELOG.md +++ b/appcenter-crashes/CHANGELOG.md @@ -1,6 +1,8 @@ # Change Log -## Features +## 0.3.0 + +### Features * Add hasCrashedInLastSession api * Add lastSessionCrashReport api From 73234565962aca98c735c8ecc29173b6c9ab0846 Mon Sep 17 00:00:00 2001 From: John Borges Date: Mon, 21 Jun 2021 21:18:58 -0400 Subject: [PATCH 24/27] refactor(appcenter): use latest shared pod --- appcenter/CapacitorCommunityAppcenter.podspec | 2 +- appcenter/ios/Podfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appcenter/CapacitorCommunityAppcenter.podspec b/appcenter/CapacitorCommunityAppcenter.podspec index 3e6c6a3..8d2a6b0 100644 --- a/appcenter/CapacitorCommunityAppcenter.podspec +++ b/appcenter/CapacitorCommunityAppcenter.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' s.ios.deployment_target = '12.0' s.dependency 'Capacitor' - s.dependency 'AppCenterCapacitorShared', '0.3.0' + s.dependency 'AppCenterCapacitorShared', '0.3.1' s.static_framework = true s.swift_version = '5.1' end diff --git a/appcenter/ios/Podfile b/appcenter/ios/Podfile index 0ad0511..51dec30 100644 --- a/appcenter/ios/Podfile +++ b/appcenter/ios/Podfile @@ -9,7 +9,7 @@ end target 'Plugin' do capacitor_pods - pod 'AppCenterCapacitorShared', '0.3.0' + pod 'AppCenterCapacitorShared', '0.3.1' end target 'PluginTests' do From d8f42921db7131b281a3134831b2b2901b09fb01 Mon Sep 17 00:00:00 2001 From: John Borges Date: Mon, 21 Jun 2021 21:19:25 -0400 Subject: [PATCH 25/27] chore(appcenter): add missing license file --- appcenter/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 appcenter/LICENSE diff --git a/appcenter/LICENSE b/appcenter/LICENSE new file mode 100644 index 0000000..9c5a1fa --- /dev/null +++ b/appcenter/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) COPYRIGHT_YEAR COPYRIGHT_HOLDER + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file From dc9bba933f8e53081ddc12eb3648cbc8a7747f42 Mon Sep 17 00:00:00 2001 From: John Borges Date: Mon, 21 Jun 2021 21:20:27 -0400 Subject: [PATCH 26/27] feat(appcenter): add networkRequestsAllowed api --- appcenter/CHANGELOG.md | 11 +++ appcenter/README.md | 43 +++++++--- .../ios/Plugin.xcodeproj/project.pbxproj | 84 +++++++++---------- appcenter/ios/Plugin/AppCenterBase.swift | 9 ++ appcenter/ios/Plugin/AppCenterPlugin.m | 9 +- appcenter/ios/Plugin/AppCenterPlugin.swift | 6 +- appcenter/package.json | 4 +- appcenter/src/definitions.ts | 32 ++++--- appcenter/src/web.ts | 6 ++ 9 files changed, 132 insertions(+), 72 deletions(-) diff --git a/appcenter/CHANGELOG.md b/appcenter/CHANGELOG.md index e69de29..dab6e3d 100644 --- a/appcenter/CHANGELOG.md +++ b/appcenter/CHANGELOG.md @@ -0,0 +1,11 @@ +# Change Log + +## 0.4.0 + +### Features + +* Add networkRequestsAllowed api + +### Bug Fixes + +* fix plugin methods with void returns (iOS) \ No newline at end of file diff --git a/appcenter/README.md b/appcenter/README.md index 2775650..e86c00c 100644 --- a/appcenter/README.md +++ b/appcenter/README.md @@ -7,9 +7,9 @@

- - - + + +
@@ -71,10 +71,11 @@ const appCenterInfo = async () => { * [`setUserId(...)`](#setuserid) * [`getSdkVersion()`](#getsdkversion) * [`isEnabled()`](#isenabled) -* [`enable(...)`](#enable) +* [`setEnable(...)`](#setenable) * [`setCustomProperties(...)`](#setcustomproperties) * [`getLogLevel()`](#getloglevel) * [`setLogLevel(...)`](#setloglevel) +* [`networkRequestsAllowed(...)`](#networkrequestsallowed) * [Enums](#enums) @@ -88,8 +89,7 @@ const appCenterInfo = async () => { getInstallId() => any ``` -Returns AppCenter UUID. -For more info, please see: https://docs.microsoft.com/en-us/appcenter/sdk/other-apis/cordova#identify-installations +Returns AppCenter unique installation identifier. **Returns:** any @@ -148,21 +148,21 @@ Check if App Center is enabled or not as a whole. -------------------- -### enable(...) +### setEnable(...) ```typescript -enable(options: { enableFlag: boolean; }) => any +setEnable(options: { shouldEnable: boolean; }) => any ``` Toggle all App Center services at runtime. When disabled, the SDK won't forward any information to App Center. -| Param | Type | -| ------------- | ------------------------------------- | -| **`options`** | { enableFlag: boolean; } | +| Param | Type | +| ------------- | --------------------------------------- | +| **`options`** | { shouldEnable: boolean; } | **Returns:** any -**Since:** 0.0.1 +**Since:** 0.4.0 -------------------- @@ -223,6 +223,25 @@ Note: `setLogLevel` API can't increase logging for app startup code, before Java -------------------- +### networkRequestsAllowed(...) + +```typescript +networkRequestsAllowed(options?: { shouldAllow: boolean; } | undefined) => any +``` + +Flag indicating whether SDK can send network requests. + +| Param | Type | +| ------------- | -------------------------------------- | +| **`options`** | { shouldAllow: boolean; } | + +**Returns:** any + +**Since:** 0.4.0 + +-------------------- + + ### Enums diff --git a/appcenter/ios/Plugin.xcodeproj/project.pbxproj b/appcenter/ios/Plugin.xcodeproj/project.pbxproj index e44dc96..a36102b 100644 --- a/appcenter/ios/Plugin.xcodeproj/project.pbxproj +++ b/appcenter/ios/Plugin.xcodeproj/project.pbxproj @@ -7,15 +7,15 @@ objects = { /* Begin PBXBuildFile section */ - 4ACBCC7661E81CDA416A43A0 /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 466E43274355C1DEF3AFB927 /* Pods_Plugin.framework */; }; 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFF88201F53D600D50D53 /* Plugin.framework */; }; 50ADFF97201F53D600D50D53 /* AppCenterPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFF96201F53D600D50D53 /* AppCenterPluginTests.swift */; }; 50ADFF99201F53D600D50D53 /* AppCenterPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 50ADFF8B201F53D600D50D53 /* AppCenterPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFFA52020D75100D50D53 /* Capacitor.framework */; }; 50ADFFA82020EE4F00D50D53 /* AppCenterPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* AppCenterPlugin.m */; }; 50E1A94820377CB70090CE1A /* AppCenterPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* AppCenterPlugin.swift */; }; - 6B57A9ACD368D3917BCB44BB /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 99680ABACC85EBB08BD396A7 /* Pods_PluginTests.framework */; }; 6CC0D08825F29C48008EDBD4 /* AppCenterBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC0D08725F29C48008EDBD4 /* AppCenterBase.swift */; }; + 80E752D1C400E92008358347 /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B606C70444D9B72CDF4DF1BA /* Pods_PluginTests.framework */; }; + E96ECB6B3A1FEE3D5402764B /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D00178D56377FE98D66C469 /* Pods_Plugin.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -29,8 +29,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 34DE9850B83F16A22940CE56 /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = ""; }; - 466E43274355C1DEF3AFB927 /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3FBFC95DB487FF8B1925F800 /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; 50ADFF88201F53D600D50D53 /* Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50ADFF8B201F53D600D50D53 /* AppCenterPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppCenterPlugin.h; sourceTree = ""; }; 50ADFF8C201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -41,10 +40,11 @@ 50ADFFA72020EE4F00D50D53 /* AppCenterPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppCenterPlugin.m; sourceTree = ""; }; 50E1A94720377CB70090CE1A /* AppCenterPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCenterPlugin.swift; sourceTree = ""; }; 6CC0D08725F29C48008EDBD4 /* AppCenterBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCenterBase.swift; sourceTree = ""; }; - 99680ABACC85EBB08BD396A7 /* Pods_PluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - AB86D69A3C5533F7F81E048D /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; - AD15C13095AF876061520CE1 /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = ""; }; - B44FAB6B78630D057216C3D0 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = ""; }; + 8DB2EB6AFE25B9ACEC1F7393 /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = ""; }; + 9C5B7C8E91825BDAA166F586 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = ""; }; + 9D00178D56377FE98D66C469 /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + A17380F937F32E2B08D6F68A /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = ""; }; + B606C70444D9B72CDF4DF1BA /* Pods_PluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -53,7 +53,7 @@ buildActionMask = 2147483647; files = ( 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */, - 4ACBCC7661E81CDA416A43A0 /* Pods_Plugin.framework in Frameworks */, + E96ECB6B3A1FEE3D5402764B /* Pods_Plugin.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -62,7 +62,7 @@ buildActionMask = 2147483647; files = ( 50ADFF92201F53D600D50D53 /* Plugin.framework in Frameworks */, - 6B57A9ACD368D3917BCB44BB /* Pods_PluginTests.framework in Frameworks */, + 80E752D1C400E92008358347 /* Pods_PluginTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -72,10 +72,10 @@ 08023BB752E022AF76EAC673 /* Pods */ = { isa = PBXGroup; children = ( - 34DE9850B83F16A22940CE56 /* Pods-Plugin.debug.xcconfig */, - AD15C13095AF876061520CE1 /* Pods-Plugin.release.xcconfig */, - AB86D69A3C5533F7F81E048D /* Pods-PluginTests.debug.xcconfig */, - B44FAB6B78630D057216C3D0 /* Pods-PluginTests.release.xcconfig */, + 8DB2EB6AFE25B9ACEC1F7393 /* Pods-Plugin.debug.xcconfig */, + A17380F937F32E2B08D6F68A /* Pods-Plugin.release.xcconfig */, + 3FBFC95DB487FF8B1925F800 /* Pods-PluginTests.debug.xcconfig */, + 9C5B7C8E91825BDAA166F586 /* Pods-PluginTests.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -125,8 +125,8 @@ isa = PBXGroup; children = ( 50ADFFA52020D75100D50D53 /* Capacitor.framework */, - 466E43274355C1DEF3AFB927 /* Pods_Plugin.framework */, - 99680ABACC85EBB08BD396A7 /* Pods_PluginTests.framework */, + 9D00178D56377FE98D66C469 /* Pods_Plugin.framework */, + B606C70444D9B72CDF4DF1BA /* Pods_PluginTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -149,7 +149,7 @@ isa = PBXNativeTarget; buildConfigurationList = 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */; buildPhases = ( - F161FCB57AD28F303325DD41 /* [CP] Check Pods Manifest.lock */, + 734BFDC83F48EDE5A658FEA1 /* [CP] Check Pods Manifest.lock */, 50ADFF83201F53D600D50D53 /* Sources */, 50ADFF84201F53D600D50D53 /* Frameworks */, 50ADFF85201F53D600D50D53 /* Headers */, @@ -168,11 +168,11 @@ isa = PBXNativeTarget; buildConfigurationList = 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */; buildPhases = ( - 94B3594F94E158EF5C0A48E8 /* [CP] Check Pods Manifest.lock */, + 8D0EAB635C65CA43ADFCFFA3 /* [CP] Check Pods Manifest.lock */, 50ADFF8D201F53D600D50D53 /* Sources */, 50ADFF8E201F53D600D50D53 /* Frameworks */, 50ADFF8F201F53D600D50D53 /* Resources */, - 75F949DFDF4366D95AB56D48 /* [CP] Embed Pods Frameworks */, + F85905F15FF667632E85057B /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -243,27 +243,29 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 75F949DFDF4366D95AB56D48 /* [CP] Embed Pods Frameworks */ = { + 734BFDC83F48EDE5A658FEA1 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/Capacitor/Capacitor.framework", - "${BUILT_PRODUCTS_DIR}/CapacitorCordova/Cordova.framework", + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( ); - name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Capacitor.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cordova.framework", + "$(DERIVED_FILE_DIR)/Pods-Plugin-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 94B3594F94E158EF5C0A48E8 /* [CP] Check Pods Manifest.lock */ = { + 8D0EAB635C65CA43ADFCFFA3 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -285,26 +287,24 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - F161FCB57AD28F303325DD41 /* [CP] Check Pods Manifest.lock */ = { + F85905F15FF667632E85057B /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Capacitor/Capacitor.framework", + "${BUILT_PRODUCTS_DIR}/CapacitorCordova/Cordova.framework", ); + name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Plugin-checkManifestLockResult.txt", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Capacitor.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cordova.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -466,7 +466,7 @@ }; 50ADFF9D201F53D600D50D53 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 34DE9850B83F16A22940CE56 /* Pods-Plugin.debug.xcconfig */; + baseConfigurationReference = 8DB2EB6AFE25B9ACEC1F7393 /* Pods-Plugin.debug.xcconfig */; buildSettings = { CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; @@ -491,7 +491,7 @@ }; 50ADFF9E201F53D600D50D53 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = AD15C13095AF876061520CE1 /* Pods-Plugin.release.xcconfig */; + baseConfigurationReference = A17380F937F32E2B08D6F68A /* Pods-Plugin.release.xcconfig */; buildSettings = { CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; @@ -515,7 +515,7 @@ }; 50ADFFA0201F53D600D50D53 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = AB86D69A3C5533F7F81E048D /* Pods-PluginTests.debug.xcconfig */; + baseConfigurationReference = 3FBFC95DB487FF8B1925F800 /* Pods-PluginTests.debug.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = PluginTests/Info.plist; @@ -529,7 +529,7 @@ }; 50ADFFA1201F53D600D50D53 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = B44FAB6B78630D057216C3D0 /* Pods-PluginTests.release.xcconfig */; + baseConfigurationReference = 9C5B7C8E91825BDAA166F586 /* Pods-PluginTests.release.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = PluginTests/Info.plist; diff --git a/appcenter/ios/Plugin/AppCenterBase.swift b/appcenter/ios/Plugin/AppCenterBase.swift index ce428ee..1114767 100644 --- a/appcenter/ios/Plugin/AppCenterBase.swift +++ b/appcenter/ios/Plugin/AppCenterBase.swift @@ -4,6 +4,15 @@ import AppCenter @objc public class AppCenterBase: NSObject { + public func networkRequestsAllowed(_ shouldAllow: Bool?) -> Bool { + guard let setAllow = shouldAllow else { + return AppCenter.networkRequestsAllowed + } + + AppCenter.networkRequestsAllowed = setAllow + return AppCenter.networkRequestsAllowed + } + public func setLogLevel(_ level: Int) { AppCenter.logLevel = LogLevel.init(rawValue: UInt(level)) ?? .verbose } diff --git a/appcenter/ios/Plugin/AppCenterPlugin.m b/appcenter/ios/Plugin/AppCenterPlugin.m index 4d5b912..68da49b 100644 --- a/appcenter/ios/Plugin/AppCenterPlugin.m +++ b/appcenter/ios/Plugin/AppCenterPlugin.m @@ -5,11 +5,12 @@ // each method the plugin supports using the CAP_PLUGIN_METHOD macro. CAP_PLUGIN(AppCenterPlugin, "AppCenter", CAP_PLUGIN_METHOD(getInstallId, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(setUserId, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(setUserId, CAPPluginReturnNone); CAP_PLUGIN_METHOD(getSdkVersion, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(isEnabled, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(enable, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(setCustomProperties, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(setEnable, CAPPluginReturnNone); + CAP_PLUGIN_METHOD(setCustomProperties, CAPPluginReturnNone); CAP_PLUGIN_METHOD(getLogLevel, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(setLogLevel, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(setLogLevel, CAPPluginReturnNone); + CAP_PLUGIN_METHOD(networkRequestsAllowed, CAPPluginReturnPromise); ) diff --git a/appcenter/ios/Plugin/AppCenterPlugin.swift b/appcenter/ios/Plugin/AppCenterPlugin.swift index 98615c4..3a2e7a9 100644 --- a/appcenter/ios/Plugin/AppCenterPlugin.swift +++ b/appcenter/ios/Plugin/AppCenterPlugin.swift @@ -28,7 +28,7 @@ public class AppCenterPlugin: CAPPlugin { } @objc func enable(_ call: CAPPluginCall) { - implementation.enable(call.getBool("enableFlag") ?? false) + implementation.enable(call.getBool("shouldEnable") ?? false) call.resolve() } @@ -52,4 +52,8 @@ public class AppCenterPlugin: CAPPlugin { call.resolve() } + + @objc func networkRequestsAllowed(_ call: CAPPluginCall) { + call.resolve(["value:": implementation.networkRequestsAllowed(call.getBool("shouldAllow"))]) + } } diff --git a/appcenter/package.json b/appcenter/package.json index 9d32df9..a24bf93 100644 --- a/appcenter/package.json +++ b/appcenter/package.json @@ -1,7 +1,7 @@ { "name": "@capacitor-community/appcenter", - "version": "0.3.4", - "description": "Capacitor Plugin for Microsoft's Visual Studio App Center SDK.", + "version": "0.4.0", + "description": "Capacitor Plugin for Microsoft's App Center SDK.", "main": "dist/plugin.cjs.js", "module": "dist/esm/index.js", "types": "dist/esm/index.d.ts", diff --git a/appcenter/src/definitions.ts b/appcenter/src/definitions.ts index 1691b7d..9434960 100644 --- a/appcenter/src/definitions.ts +++ b/appcenter/src/definitions.ts @@ -75,8 +75,7 @@ export class CustomProperties implements ICustomProperties { export interface AppCenterPlugin { /** - * Returns AppCenter UUID. - * For more info, please see: https://docs.microsoft.com/en-us/appcenter/sdk/other-apis/cordova#identify-installations + * Returns AppCenter unique installation identifier. * @returns {Promise<{value: string}>} install id * @since 0.0.1 * @example @@ -87,8 +86,7 @@ export interface AppCenterPlugin { getInstallId(): Promise<{value: string}>; /** * Set a user ID that's used to augment crash reports. - * For more info, please see: https://docs.microsoft.com/en-us/appcenter/sdk/other-apis/cordova#identify-users - * @param {userId: string} options Ex. "your-user-id" + * @param {{userId: string}} options Ex. "your-user-id" * @returns {Promise} * @since 0.0.1 * @example @@ -122,19 +120,19 @@ export interface AppCenterPlugin { /** * Toggle all App Center services at runtime. When disabled, the SDK won't forward any information to App Center. - * @param {enableFlag: boolean} options - * @since 0.0.1 + * @param {{shouldEnable: boolean}} options + * @since 0.4.0 * @example * import AppCenter from '@capacitor-community/appcenter'; - * await AppCenter.enable({enableFlag: true}); + * await AppCenter.setEnable({shouldEnable: true}); */ - enable(options: {enableFlag: boolean}): Promise; + setEnable(options: {shouldEnable: boolean}): Promise; /** * App Center allows you to define custom properties as key value pairs in your app. You may use custom properties for various purposes. * For instance, you can use custom properties to segment your users, and then send push notifications to a specific audience. - * @param {properties: CustomProperties} options + * @param {{properties: CustomProperties}} options * @since 0.2.0 * @example * import AppCenter, { CustomProperties } from '@capacitor-community/appcenter'; @@ -152,7 +150,7 @@ export interface AppCenterPlugin { * @example * import AppCenter from '@capacitor-community/appcenter'; * - * const {value: logLevel } = await AppCenter.getLogLevel() + * const {value: logLevel} = await AppCenter.getLogLevel() */ getLogLevel(): Promise<{value: LogLevel}>; @@ -160,7 +158,7 @@ export interface AppCenterPlugin { * You can control the amount of log messages that show up from App Center in the console. Log messages show in the console on iOS and LogCat on Android. * By default, it's set to Assert for the App Store environment and Warning otherwise. To have as many log messages as possible, use Verbose. * Note: `setLogLevel` API can't increase logging for app startup code, before JavaScript is loaded. - * @param {{logLevel: LogLevel}} options + * @param {logLevel: LogLevel} options * @since 0.2.0 * @example * import AppCenter, { LogLevel } from '@capacitor-community/appcenter'; @@ -169,6 +167,18 @@ export interface AppCenterPlugin { */ setLogLevel(options: {logLevel: LogLevel}): Promise; + /** + * Flag indicating whether SDK can send network requests. + * @param {{shouldAllow: boolean}} options + * @returns {Promise<{value: boolean}>} + * @since 0.4.0 + * @example + * import AppCenterfrom '@capacitor-community/appcenter'; + * + * const {value: allowed} = await AppCenter.networkRequestsAllowed({shouldAllow: true}) + */ + networkRequestsAllowed(options?: {shouldAllow: boolean}): Promise<{value: boolean}> + // move to confg setting in appcenter-analytics // setMaxStorageSize } \ No newline at end of file diff --git a/appcenter/src/web.ts b/appcenter/src/web.ts index f85fa46..0e17d3a 100644 --- a/appcenter/src/web.ts +++ b/appcenter/src/web.ts @@ -3,6 +3,12 @@ import { WebPlugin } from '@capacitor/core'; import { AppCenterPlugin, LogLevel } from './definitions'; export class AppCenterWeb extends WebPlugin implements AppCenterPlugin { + setEnable(): Promise { + throw this.unimplemented('Not supported on web.'); + } + networkRequestsAllowed(): Promise<{ value: boolean; }> { + throw new Error('Method not implemented.'); + } setLogLevel(): Promise { throw this.unimplemented('Not supported on web.'); } From 1603b8e616ebfdcd0cda371819099a396d6268a7 Mon Sep 17 00:00:00 2001 From: John Borges Date: Wed, 23 Jun 2021 17:40:20 -0400 Subject: [PATCH 27/27] chore(example): use latest plugin --- example/package.json | 4 ++-- example/src/components/app-home/app-home.tsx | 24 ++++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/example/package.json b/example/package.json index ed5c2fd..4ed5046 100644 --- a/example/package.json +++ b/example/package.json @@ -19,9 +19,9 @@ "@stencil/core": "^2.0.1" }, "dependencies": { - "@capacitor-community/appcenter": "0.3.4", + "@capacitor-community/appcenter": "^0.4.0", "@capacitor-community/appcenter-analytics": "0.2.0", - "@capacitor-community/appcenter-crashes": "0.2.0", + "@capacitor-community/appcenter-crashes": "^0.3.0", "@capacitor/app": "^1.0.0", "@capacitor/cli": "3.0.0", "@capacitor/core": "3.0.0", diff --git a/example/src/components/app-home/app-home.tsx b/example/src/components/app-home/app-home.tsx index b2023f1..2200c94 100644 --- a/example/src/components/app-home/app-home.tsx +++ b/example/src/components/app-home/app-home.tsx @@ -15,7 +15,9 @@ export class AppHome { /* App Center userId */ userId: string; /* Flag to toggle App Center SDK */ - @State() enabled: boolean = false; + @State() enabled: boolean = false + /* Flag to toggle App Center network requests */ + @State() networkReqAllowed: boolean = false /* App Center LogLevel */ @State() logLevel: LogLevel; @@ -23,6 +25,7 @@ export class AppHome { this.updateUserId = this.updateUserId.bind(this); this.toggleSdk = this.toggleSdk.bind(this); this.setLogLevel = this.setLogLevel.bind(this); + this.toggleNetwork = this.toggleNetwork.bind(this) } async componentWillLoad() { @@ -30,6 +33,7 @@ export class AppHome { try { const { value: sdkEnabled } = await AppCenter.isEnabled() + const { value: reqAllowed } = await AppCenter.networkRequestsAllowed() const { value: installId } = await AppCenter.getInstallId() const { value: sdkVersion } = await AppCenter.getSdkVersion() const { value: logLevel } = await AppCenter.getLogLevel() @@ -38,6 +42,7 @@ export class AppHome { this.sdkVersion = sdkVersion this.enabled = sdkEnabled this.logLevel = logLevel + this.networkReqAllowed = reqAllowed console.debug(logLevel) @@ -84,7 +89,7 @@ export class AppHome { async toggleSdk(e: CustomEvent) { console.debug("[homepage] toggleSdk"); try { - await AppCenter.enable({enableFlag: e.detail.checked}); + await AppCenter.setEnable({shouldEnable: e.detail.checked}); this.enabled = e.detail.checked } catch (error) { this.enabled = false @@ -92,6 +97,17 @@ export class AppHome { } } + async toggleNetwork(e: CustomEvent) { + console.debug("[homepage] toggleNetwork"); + try { + await AppCenter.networkRequestsAllowed({shouldAllow: e.detail.checked}); + this.networkReqAllowed = e.detail.checked + } catch (error) { + this.enabled = false + console.error(error) + } + } + async setLogLevel(logLevel: LogLevel) { try { await AppCenter.setLogLevel({logLevel: logLevel}) @@ -121,6 +137,10 @@ export class AppHome { App Center SDK {this.sdkVersion} + + Allow Network Requests + this.toggleNetwork(event)} /> + Log Level this.setLogLevel(event.detail.value)}>