From 0d1988b5a025de85b7f9839eddf49c2ddcb39689 Mon Sep 17 00:00:00 2001 From: John Borges Date: Mon, 29 Mar 2021 09:29:09 -0400 Subject: [PATCH 1/9] 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 2/9] 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 3/9] 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 4/9] 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 5/9] 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 6/9] 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 7/9] 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 8/9] 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 9/9] 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)} /> + + + , + ]; + } }