diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 25f8d143..0f22a141 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,26 +2,22 @@ name: CI on: pull_request: branches: - - '**' + - "**" paths-ignore: - - '.github/**' - - '.vscode/**' - - 'README.md' + - ".github/**" + - ".vscode/**" + - "README.md" workflow_dispatch: jobs: build: runs-on: ubuntu-latest + container: + image: ghcr.io/cirruslabs/flutter:3.35.5 steps: - - name: Setup Flutter - uses: subosito/flutter-action@v2 - with: - flutter-version: '3.3.2' - channel: 'stable' - - name: Checkout OneSignal-Flutter-SDK - uses: actions/checkout@v3 + uses: actions/checkout@v5 - name: Install Dependencies 🔗⛓📦 run: flutter pub get @@ -30,7 +26,7 @@ jobs: run: flutter analyze - name: Ensure the Dart code is formatted correctly - run: flutter format --set-exit-if-changed --dry-run . + run: dart format --set-exit-if-changed --output=none . - name: Run Flutter unit tests run: flutter test diff --git a/.gitignore b/.gitignore index 4999ea3b..3266facd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,11 +4,13 @@ .packages .pub/ pubspec.lock +**/local.properties build/ android/.idea .flutter-plugins-dependencies flutter_export_environment.sh +example/ios/Flutter/ephemeral/ # IntelliJ related *.iml diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..e59845b1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "[objective-c]": { + "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" + } +} diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar index 13372aef..d64cd491 100644 Binary files a/android/gradle/wrapper/gradle-wrapper.jar and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradlew b/android/gradlew old mode 100644 new mode 100755 index 9d82f789..1aa94a42 --- a/android/gradlew +++ b/android/gradlew @@ -1,74 +1,127 @@ -#!/usr/bin/env bash +#!/bin/sh + +# +# Copyright © 2015-2021 the original 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 -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum -warn ( ) { +warn () { echo "$*" -} +} >&2 -die ( ) { +die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac -# 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 - 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" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -77,84 +130,120 @@ 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. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + 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 fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac 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 +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - 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\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +# 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"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat index aec99730..6689b85b 100644 --- a/android/gradlew.bat +++ b/android/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@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 @@ -8,20 +24,24 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused 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 +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,44 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 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 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/android/src/main/java/com/onesignal/flutter/OneSignalUser.java b/android/src/main/java/com/onesignal/flutter/OneSignalUser.java index de70f165..4dfa7354 100644 --- a/android/src/main/java/com/onesignal/flutter/OneSignalUser.java +++ b/android/src/main/java/com/onesignal/flutter/OneSignalUser.java @@ -16,7 +16,8 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; -public class OneSignalUser extends FlutterMessengerResponder implements MethodCallHandler, IUserStateObserver { +public class OneSignalUser extends FlutterMessengerResponder + implements MethodCallHandler, IUserStateObserver { static void registerWith(BinaryMessenger messenger) { OneSignalUser controller = new OneSignalUser(); @@ -76,7 +77,7 @@ private void getOnesignalId(MethodCall call, Result result) { onesignalId = null; } replySuccess(result, onesignalId); - } + } private void getExternalId(MethodCall call, Result result) { String externalId = OneSignal.getUser().getExternalId(); @@ -85,26 +86,30 @@ private void getExternalId(MethodCall call, Result result) { } replySuccess(result, externalId); } - + private void addAliases(MethodCall call, Result result) { // call.arguments is being casted to a Map so a try-catch with - // a ClassCastException will be thrown + // a ClassCastException will be thrown try { OneSignal.getUser().addAliases((Map) call.arguments); replySuccess(result, null); - } catch(ClassCastException e) { - replyError(result, "OneSignal", "addAliases failed with error: " + e.getMessage() + "\n" + e.getStackTrace(), null); + } catch (ClassCastException e) { + replyError(result, "OneSignal", + "addAliases failed with error: " + e.getMessage() + "\n" + e.getStackTrace(), + null); } } private void removeAliases(MethodCall call, Result result) { // call.arguments is being casted to a List so a try-catch with - // a ClassCastException will be thrown + // a ClassCastException will be thrown try { OneSignal.getUser().removeAliases((List) call.arguments); replySuccess(result, null); - } catch(ClassCastException e) { - replyError(result, "OneSignal", "removeAliases failed with error: " + e.getMessage() + "\n" + e.getStackTrace(), null); + } catch (ClassCastException e) { + replyError(result, "OneSignal", + "removeAliases failed with error: " + e.getMessage() + "\n" + e.getStackTrace(), + null); } } @@ -112,17 +117,17 @@ private void addEmail(MethodCall call, Result result) { OneSignal.getUser().addEmail((String) call.arguments); replySuccess(result, null); } - + private void removeEmail(MethodCall call, Result result) { OneSignal.getUser().removeEmail((String) call.arguments); replySuccess(result, null); } - + private void addSms(MethodCall call, Result result) { OneSignal.getUser().addSms((String) call.arguments); replySuccess(result, null); } - + private void removeSms(MethodCall call, Result result) { OneSignal.getUser().removeSms((String) call.arguments); replySuccess(result, null); @@ -130,23 +135,27 @@ private void removeSms(MethodCall call, Result result) { private void addTags(MethodCall call, Result result) { // call.arguments is being casted to a Map so a try-catch with - // a ClassCastException will be thrown + // a ClassCastException will be thrown try { OneSignal.getUser().addTags((Map) call.arguments); replySuccess(result, null); - } catch(ClassCastException e) { - replyError(result, "OneSignal", "addTags failed with error: " + e.getMessage() + "\n" + e.getStackTrace(), null); + } catch (ClassCastException e) { + replyError(result, "OneSignal", + "addTags failed with error: " + e.getMessage() + "\n" + e.getStackTrace(), + null); } } private void removeTags(MethodCall call, Result result) { // call.arguments is being casted to a List so a try-catch with - // a ClassCastException will be thrown + // a ClassCastException will be thrown try { OneSignal.getUser().removeTags((List) call.arguments); replySuccess(result, null); - } catch(ClassCastException e) { - replyError(result, "OneSignal", "deleteTags failed with error: " + e.getMessage() + "\n" + e.getStackTrace(), null); + } catch (ClassCastException e) { + replyError(result, "OneSignal", + "deleteTags failed with error: " + e.getMessage() + "\n" + e.getStackTrace(), + null); } } @@ -157,10 +166,14 @@ private void getTags(MethodCall call, Result result) { @Override public void onUserStateChange(UserChangedState userChangedState) { try { - invokeMethodOnUiThread("OneSignal#onUserStateChange", OneSignalSerializer.convertOnUserStateChange(userChangedState)); + invokeMethodOnUiThread("OneSignal#onUserStateChange", + OneSignalSerializer.convertOnUserStateChange(userChangedState)); } catch (JSONException e) { e.getStackTrace(); - Logging.error("Encountered an error attempting to convert UserChangedState object to hash map:" + e.toString(), null); + Logging.error( + "Encountered an error attempting to convert UserChangedState object to hash map:" + + e.toString(), + null); } } } diff --git a/example/.metadata b/example/.metadata index 82403edb..0f6195d3 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,5 +4,27 @@ # This file should be version controlled and should not be manually edited. version: - revision: c7ea3ca377e909469c68f2ab878a5bc53d3cf66b - channel: beta + revision: "ac4e799d237041cf905519190471f657b657155a" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: ac4e799d237041cf905519190471f657b657155a + base_revision: ac4e799d237041cf905519190471f657b657155a + - platform: android + create_revision: ac4e799d237041cf905519190471f657b657155a + base_revision: ac4e799d237041cf905519190471f657b657155a + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/example/README.md b/example/README.md index 0c261ed4..13327bf6 100644 --- a/example/README.md +++ b/example/README.md @@ -2,6 +2,30 @@ Demonstrates how to use the onesignal plugin. +# iOS + +First you may need to run `pod install` in the ios folder. +Then launch a simulator then you can run `flutter run`. + +# Android + +Make sure you have the Android SDK cli tools and have accepted the license agreements. +E.g. + +``` +flutter doctor --android-licenses +``` + +Then launch an Android emulator e.g. + +``` +flutter emulators --launch Medium_Phone_API_35; +``` + +And then you can run `flutter run`. + +If you are using an older Flutter or Android Studio version, you may see an error about `ndkVersion`. Follow the instructions to update the version in `build.gradle.kts`. + ## Getting Started For help getting started with Flutter, view our online diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml new file mode 100644 index 00000000..241a690a --- /dev/null +++ b/example/analysis_options.yaml @@ -0,0 +1,41 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # Disable style lints for example app + avoid_print: false + unnecessary_new: false + unnecessary_this: false + prefer_const_constructors: false + prefer_const_constructors_in_immutables: false + use_key_in_widget_constructors: false + library_private_types_in_public_api: false + prefer_final_fields: false + prefer_interpolation_to_compose_strings: false + prefer_collection_literals: false + sort_child_properties_last: false + prefer_generic_function_type_aliases: false + annotate_overrides: false + depend_on_referenced_packages: false + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/example/android/.gitignore b/example/android/.gitignore index 65b7315a..be3943c9 100644 --- a/example/android/.gitignore +++ b/example/android/.gitignore @@ -1,10 +1,14 @@ -*.iml -*.class -.gradle +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat /local.properties -/.idea/workspace.xml -/.idea/libraries -.DS_Store -/build -/captures GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle deleted file mode 100644 index c4c20061..00000000 --- a/example/android/app/build.gradle +++ /dev/null @@ -1,51 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -apply plugin: 'com.android.application' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 34 - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.onesignal.onesignalexample" - minSdkVersion 19 - targetSdkVersion 33 - versionCode 1 - versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' -} diff --git a/example/android/app/build.gradle.kts b/example/android/app/build.gradle.kts new file mode 100644 index 00000000..5001623b --- /dev/null +++ b/example/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.onesignal.onesignal_example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.onesignal.onesignal_example" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index b88b7888..4dc65895 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,32 +1,15 @@ - - - - - - - - - - - - + - - + android:name="io.flutter.embedding.android.NormalTheme" + android:resource="@style/NormalTheme" + /> @@ -57,4 +31,15 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + diff --git a/example/android/app/src/main/java/com/onesignal/onesignalexample/MainActivity.java b/example/android/app/src/main/java/com/onesignal/onesignalexample/MainActivity.java deleted file mode 100644 index 30811875..00000000 --- a/example/android/app/src/main/java/com/onesignal/onesignalexample/MainActivity.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.onesignal.onesignalexample; - -import io.flutter.embedding.android.FlutterActivity; - -public class MainActivity extends FlutterActivity { -} diff --git a/example/android/app/src/main/kotlin/com/onesignal/onesignal_example/MainActivity.kt b/example/android/app/src/main/kotlin/com/onesignal/onesignal_example/MainActivity.kt new file mode 100644 index 00000000..5be0b3b4 --- /dev/null +++ b/example/android/app/src/main/kotlin/com/onesignal/onesignal_example/MainActivity.kt @@ -0,0 +1,5 @@ +package com.onesignal.onesignal_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml index 723556da..cb1ef880 100644 --- a/example/android/app/src/main/res/values/styles.xml +++ b/example/android/app/src/main/res/values/styles.xml @@ -1,11 +1,18 @@ - - diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/build.gradle b/example/android/build.gradle deleted file mode 100644 index 08cb0aa3..00000000 --- a/example/android/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -buildscript { - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.0.0' - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/example/android/build.gradle.kts b/example/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/example/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 8b001ac7..f018a618 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,7 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M - -android.enableR8=true -android.enableD8=true - +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 14af8e8e..02767eb1 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Thu Oct 17 15:00:44 PDT 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip \ No newline at end of file +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/example/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts new file mode 100644 index 00000000..75af8a40 --- /dev/null +++ b/example/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.13.0" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 7c569640..1dc6cf76 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 12.0 + 13.0 diff --git a/example/ios/Flutter/Flutter.podspec b/example/ios/Flutter/Flutter.podspec index 98e16339..3aed58d3 100644 --- a/example/ios/Flutter/Flutter.podspec +++ b/example/ios/Flutter/Flutter.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.license = { :type => 'BSD' } s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' # Framework linking is handled by Flutter tooling, not CocoaPods. # Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs. s.vendored_frameworks = 'path/to/nothing' diff --git a/example/ios/Podfile b/example/ios/Podfile index 33fe22f4..2f6ad5d0 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '12.0' +platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 6f5efb0f..dde1f068 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,11 +1,11 @@ PODS: - Flutter (1.0.0) - - onesignal_flutter (5.1.5): + - onesignal_flutter (5.3.4): - Flutter - - OneSignalXCFramework (= 5.2.0) - - OneSignalXCFramework (5.2.0): - - OneSignalXCFramework/OneSignalComplete (= 5.2.0) - - OneSignalXCFramework/OneSignal (5.2.0): + - OneSignalXCFramework (= 5.2.14) + - OneSignalXCFramework (5.2.14): + - OneSignalXCFramework/OneSignalComplete (= 5.2.14) + - OneSignalXCFramework/OneSignal (5.2.14): - OneSignalXCFramework/OneSignalCore - OneSignalXCFramework/OneSignalExtension - OneSignalXCFramework/OneSignalLiveActivities @@ -13,38 +13,38 @@ PODS: - OneSignalXCFramework/OneSignalOSCore - OneSignalXCFramework/OneSignalOutcomes - OneSignalXCFramework/OneSignalUser - - OneSignalXCFramework/OneSignalComplete (5.2.0): + - OneSignalXCFramework/OneSignalComplete (5.2.14): - OneSignalXCFramework/OneSignal - OneSignalXCFramework/OneSignalInAppMessages - OneSignalXCFramework/OneSignalLocation - - OneSignalXCFramework/OneSignalCore (5.2.0) - - OneSignalXCFramework/OneSignalExtension (5.2.0): + - OneSignalXCFramework/OneSignalCore (5.2.14) + - OneSignalXCFramework/OneSignalExtension (5.2.14): - OneSignalXCFramework/OneSignalCore - OneSignalXCFramework/OneSignalOutcomes - - OneSignalXCFramework/OneSignalInAppMessages (5.2.0): + - OneSignalXCFramework/OneSignalInAppMessages (5.2.14): - OneSignalXCFramework/OneSignalCore - OneSignalXCFramework/OneSignalNotifications - OneSignalXCFramework/OneSignalOSCore - OneSignalXCFramework/OneSignalOutcomes - OneSignalXCFramework/OneSignalUser - - OneSignalXCFramework/OneSignalLiveActivities (5.2.0): + - OneSignalXCFramework/OneSignalLiveActivities (5.2.14): - OneSignalXCFramework/OneSignalCore - OneSignalXCFramework/OneSignalOSCore - OneSignalXCFramework/OneSignalUser - - OneSignalXCFramework/OneSignalLocation (5.2.0): + - OneSignalXCFramework/OneSignalLocation (5.2.14): - OneSignalXCFramework/OneSignalCore - OneSignalXCFramework/OneSignalNotifications - OneSignalXCFramework/OneSignalOSCore - OneSignalXCFramework/OneSignalUser - - OneSignalXCFramework/OneSignalNotifications (5.2.0): + - OneSignalXCFramework/OneSignalNotifications (5.2.14): - OneSignalXCFramework/OneSignalCore - OneSignalXCFramework/OneSignalExtension - OneSignalXCFramework/OneSignalOutcomes - - OneSignalXCFramework/OneSignalOSCore (5.2.0): + - OneSignalXCFramework/OneSignalOSCore (5.2.14): - OneSignalXCFramework/OneSignalCore - - OneSignalXCFramework/OneSignalOutcomes (5.2.0): + - OneSignalXCFramework/OneSignalOutcomes (5.2.14): - OneSignalXCFramework/OneSignalCore - - OneSignalXCFramework/OneSignalUser (5.2.0): + - OneSignalXCFramework/OneSignalUser (5.2.14): - OneSignalXCFramework/OneSignalCore - OneSignalXCFramework/OneSignalNotifications - OneSignalXCFramework/OneSignalOSCore @@ -66,10 +66,10 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/onesignal_flutter/ios" SPEC CHECKSUMS: - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - onesignal_flutter: 6e7b22bc9bbdb32cbaf79728e624a02264adec94 - OneSignalXCFramework: bdf74fdc06888f9466dc21e826fe1549ed143095 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + onesignal_flutter: 3a2b51f9262c851166a882a553d71a8ccec4e29c + OneSignalXCFramework: 7112f3e89563e41ebc23fe807788f11985ac541c -PODFILE CHECKSUM: 4866dde54f21b323e83902730ef350ff4a561f44 +PODFILE CHECKSUM: 008ee3527530ade7ae7311fc02a615df31949c2e -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 5c4161de..e80d7352 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -745,7 +745,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -792,7 +792,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -878,7 +878,7 @@ ENABLE_BITCODE = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OneSignalNotificationServiceExtension/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -911,7 +911,7 @@ ENABLE_BITCODE = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OneSignalNotificationServiceExtension/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index cdef6845..684be6af 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> diff --git a/example/lib/main.dart b/example/lib/main.dart index dd51f862..b77b9201 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,7 +1,6 @@ -import 'package:flutter/material.dart'; import 'dart:async'; -//import OneSignal +import 'package:flutter/material.dart'; import 'package:onesignal_flutter/onesignal_flutter.dart'; void main() => runApp(new MyApp()); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 979ddb2d..a38ad68a 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -15,6 +15,7 @@ environment: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^2.0.0 onesignal_flutter: path: ../ @@ -24,7 +25,6 @@ dev_dependencies: # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. @@ -59,4 +59,4 @@ flutter: # weight: 700 # # For details regarding fonts from package dependencies, - # see https://flutter.io/custom-fonts/#from-packages \ No newline at end of file + # see https://flutter.io/custom-fonts/#from-packages diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart new file mode 100644 index 00000000..3127d8f4 --- /dev/null +++ b/example/test/widget_test.dart @@ -0,0 +1,29 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:onesignal_example/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/ios/Classes/OSFlutterUser.m b/ios/Classes/OSFlutterUser.m index 698e25e1..165b9ef8 100644 --- a/ios/Classes/OSFlutterUser.m +++ b/ios/Classes/OSFlutterUser.m @@ -13,8 +13,8 @@ * 1. The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * - * 2. All copies of substantial portions of the Software may only be used in connection - * with services provided by OneSignal. + * 2. All copies of substantial portions of the Software may only be used in + * connection with services provided by OneSignal. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, @@ -24,154 +24,157 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - #import "OSFlutterUser.h" -#import -#import #import "OSFlutterCategories.h" #import "OSFlutterPushSubscription.h" - +#import +#import @implementation OSFlutterUser -+ (void)registerWithRegistrar:(NSObject*)registrar { - OSFlutterUser *instance = [OSFlutterUser new]; - - instance.channel = [FlutterMethodChannel - methodChannelWithName:@"OneSignal#user" - binaryMessenger:[registrar messenger]]; - - [registrar addMethodCallDelegate:instance channel:instance.channel]; - [OSFlutterPushSubscription registerWithRegistrar:registrar]; -} - -- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { - if ([@"OneSignal#setLanguage" isEqualToString:call.method]) - [self setLanguage:call withResult:result]; - else if ([@"OneSignal#getOnesignalId" isEqualToString:call.method]) - [self getOnesignalId:call withResult:result]; - else if ([@"OneSignal#getExternalId" isEqualToString:call.method]) - [self getExternalId:call withResult:result]; - else if ([@"OneSignal#addAliases" isEqualToString:call.method]) - [self addAliases:call withResult:result]; - else if ([@"OneSignal#removeAliases" isEqualToString:call.method]) - [self removeAliases:call withResult:result]; - else if ([@"OneSignal#addTags" isEqualToString:call.method]) - [self addTags:call withResult:result]; - else if ([@"OneSignal#removeTags" isEqualToString:call.method]) - [self removeTags:call withResult:result]; - else if ([@"OneSignal#getTags" isEqualToString:call.method]) - [self getTags:call withResult:result]; - else if ([@"OneSignal#addEmail" isEqualToString:call.method]) - [self addEmail:call withResult:result]; - else if ([@"OneSignal#removeEmail" isEqualToString:call.method]) - [self removeEmail:call withResult:result]; - else if ([@"OneSignal#addSms" isEqualToString:call.method]) - [self addSms:call withResult:result]; - else if ([@"OneSignal#removeSms" isEqualToString:call.method]) - [self removeSms:call withResult:result]; - else if ([@"OneSignal#lifecycleInit" isEqualToString:call.method]) - [self lifecycleInit:call withResult:result]; - else - result(FlutterMethodNotImplemented); ++ (void)registerWithRegistrar:(NSObject *)registrar { + OSFlutterUser *instance = [OSFlutterUser new]; + + instance.channel = + [FlutterMethodChannel methodChannelWithName:@"OneSignal#user" + binaryMessenger:[registrar messenger]]; + + [registrar addMethodCallDelegate:instance channel:instance.channel]; + [OSFlutterPushSubscription registerWithRegistrar:registrar]; +} + +- (void)handleMethodCall:(FlutterMethodCall *)call + result:(FlutterResult)result { + if ([@"OneSignal#setLanguage" isEqualToString:call.method]) + [self setLanguage:call withResult:result]; + else if ([@"OneSignal#getOnesignalId" isEqualToString:call.method]) + [self getOnesignalId:call withResult:result]; + else if ([@"OneSignal#getExternalId" isEqualToString:call.method]) + [self getExternalId:call withResult:result]; + else if ([@"OneSignal#addAliases" isEqualToString:call.method]) + [self addAliases:call withResult:result]; + else if ([@"OneSignal#removeAliases" isEqualToString:call.method]) + [self removeAliases:call withResult:result]; + else if ([@"OneSignal#addTags" isEqualToString:call.method]) + [self addTags:call withResult:result]; + else if ([@"OneSignal#removeTags" isEqualToString:call.method]) + [self removeTags:call withResult:result]; + else if ([@"OneSignal#getTags" isEqualToString:call.method]) + [self getTags:call withResult:result]; + else if ([@"OneSignal#addEmail" isEqualToString:call.method]) + [self addEmail:call withResult:result]; + else if ([@"OneSignal#removeEmail" isEqualToString:call.method]) + [self removeEmail:call withResult:result]; + else if ([@"OneSignal#addSms" isEqualToString:call.method]) + [self addSms:call withResult:result]; + else if ([@"OneSignal#removeSms" isEqualToString:call.method]) + [self removeSms:call withResult:result]; + else if ([@"OneSignal#lifecycleInit" isEqualToString:call.method]) + [self lifecycleInit:call withResult:result]; + else + result(FlutterMethodNotImplemented); } - (void)setLanguage:(FlutterMethodCall *)call withResult:(FlutterResult)result { - id language = call.arguments[@"language"]; - if (language == [NSNull null]) { - language = nil; - } + id language = call.arguments[@"language"]; + if (language == [NSNull null]) { + language = nil; + } - [OneSignal.User setLanguage:language]; - result(nil); + [OneSignal.User setLanguage:language]; + result(nil); } - (void)addAliases:(FlutterMethodCall *)call withResult:(FlutterResult)result { - NSDictionary *aliases = call.arguments; - [OneSignal.User addAliases:aliases]; - result(nil); + NSDictionary *aliases = call.arguments; + [OneSignal.User addAliases:aliases]; + result(nil); } -- (void)removeAliases:(FlutterMethodCall *)call withResult:(FlutterResult)result { - NSDictionary *aliases = call.arguments; - [OneSignal.User removeAliases:aliases]; - result(nil); +- (void)removeAliases:(FlutterMethodCall *)call + withResult:(FlutterResult)result { + NSDictionary *aliases = call.arguments; + [OneSignal.User removeAliases:aliases]; + result(nil); } - (void)addTags:(FlutterMethodCall *)call withResult:(FlutterResult)result { - NSDictionary *tags = call.arguments; - [OneSignal.User addTags:tags]; - result(nil); + NSDictionary *tags = call.arguments; + [OneSignal.User addTags:tags]; + result(nil); } - (void)removeTags:(FlutterMethodCall *)call withResult:(FlutterResult)result { - NSDictionary *tags = call.arguments; - [OneSignal.User removeTags:tags]; - result(nil); + NSDictionary *tags = call.arguments; + [OneSignal.User removeTags:tags]; + result(nil); } - (void)getTags:(FlutterMethodCall *)call withResult:(FlutterResult)result { - result([OneSignal.User getTags]); + result([OneSignal.User getTags]); } - (void)addEmail:(FlutterMethodCall *)call withResult:(FlutterResult)result { - NSString *email = call.arguments; - [OneSignal.User addEmail:email]; - result(nil); + NSString *email = call.arguments; + [OneSignal.User addEmail:email]; + result(nil); } - (void)removeEmail:(FlutterMethodCall *)call withResult:(FlutterResult)result { - NSString *email = call.arguments; - [OneSignal.User removeEmail:email]; - result(nil); + NSString *email = call.arguments; + [OneSignal.User removeEmail:email]; + result(nil); } - (void)addSms:(FlutterMethodCall *)call withResult:(FlutterResult)result { - NSString *smsNumber = call.arguments; - [OneSignal.User addSms:smsNumber]; - result(nil); + NSString *smsNumber = call.arguments; + [OneSignal.User addSms:smsNumber]; + result(nil); } - (void)removeSms:(FlutterMethodCall *)call withResult:(FlutterResult)result { - NSString *smsNumber = call.arguments; - [OneSignal.User removeSms:smsNumber]; - result(nil); + NSString *smsNumber = call.arguments; + [OneSignal.User removeSms:smsNumber]; + result(nil); } -- (void)lifecycleInit:(FlutterMethodCall *)call withResult:(FlutterResult)result { - [OneSignal.User addObserver:self]; - result(nil); +- (void)lifecycleInit:(FlutterMethodCall *)call + withResult:(FlutterResult)result { + [OneSignal.User addObserver:self]; + result(nil); } - (void)onUserStateDidChangeWithState:(OSUserChangedState *)state { - NSString *onesignalId = [self getStringOrNSNull:state.current.onesignalId]; - NSString *externalId = [self getStringOrNSNull:state.current.externalId]; + NSString *onesignalId = [self getStringOrNSNull:state.current.onesignalId]; + NSString *externalId = [self getStringOrNSNull:state.current.externalId]; + + NSMutableDictionary *result = [NSMutableDictionary new]; + + NSMutableDictionary *currentObject = [NSMutableDictionary new]; - NSMutableDictionary *result = [NSMutableDictionary new]; - - NSMutableDictionary *currentObject = [NSMutableDictionary new]; - - currentObject[@"onesignalId"] = onesignalId; - currentObject[@"externalId"] = externalId; - result[@"current"] = currentObject; + currentObject[@"onesignalId"] = onesignalId; + currentObject[@"externalId"] = externalId; + result[@"current"] = currentObject; - [self.channel invokeMethod:@"OneSignal#onUserStateChange" arguments:result]; + [self.channel invokeMethod:@"OneSignal#onUserStateChange" arguments:result]; } -- (void)getOnesignalId:(FlutterMethodCall *)call withResult:(FlutterResult)result { - result(OneSignal.User.onesignalId); +- (void)getOnesignalId:(FlutterMethodCall *)call + withResult:(FlutterResult)result { + result(OneSignal.User.onesignalId); } -- (void)getExternalId:(FlutterMethodCall *)call withResult:(FlutterResult)result { - result(OneSignal.User.externalId); +- (void)getExternalId:(FlutterMethodCall *)call + withResult:(FlutterResult)result { + result(OneSignal.User.externalId); } /** Helper method to return NSNull if string is empty or nil **/ - (NSString *)getStringOrNSNull:(NSString *)string { - // length method can be used on nil and strings - if (string.length > 0) { - return string; - } else { - return [NSNull null]; - } + // length method can be used on nil and strings + if (string.length > 0) { + return string; + } else { + return [NSNull null]; + } } @end diff --git a/test/mock_channel.dart b/test/mock_channel.dart index d062038a..6cb35b43 100644 --- a/test/mock_channel.dart +++ b/test/mock_channel.dart @@ -1,6 +1,6 @@ import 'package:flutter/services.dart'; -import 'package:onesignal_flutter/onesignal_flutter.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:onesignal_flutter/onesignal_flutter.dart'; /* This class mocks an iOS or Android host device @@ -9,16 +9,19 @@ import 'package:flutter_test/flutter_test.dart'; */ class OneSignalMockChannelController { - MethodChannel _channel = const MethodChannel('OneSignal'); - MethodChannel _debugChannel = const MethodChannel('OneSignal#debug'); - MethodChannel _tagsChannel = const MethodChannel('OneSignal#tags'); + final MethodChannel _channel = const MethodChannel('OneSignal'); + final MethodChannel _debugChannel = const MethodChannel('OneSignal#debug'); + final MethodChannel _tagsChannel = const MethodChannel('OneSignal#tags'); late OneSignalState state; OneSignalMockChannelController() { - this._channel.setMockMethodCallHandler(_handleMethod); - this._tagsChannel.setMockMethodCallHandler(_handleMethod); - this._debugChannel.setMockMethodCallHandler(_handleMethod); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(_channel, _handleMethod); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(_tagsChannel, _handleMethod); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(_debugChannel, _handleMethod); } void resetState() { @@ -29,49 +32,48 @@ class OneSignalMockChannelController { print("Mock method called: ${call.method}"); switch (call.method) { case "OneSignal#setAppId": - this.state.setAppId(call.arguments); + state.setAppId(call.arguments); break; case "OneSignal#setLogLevel": - this.state.setLogLevel(call.arguments); + state.setLogLevel(call.arguments); break; case "OneSignal#consentGiven": - this.state.consentGiven = + state.consentGiven = (call.arguments as Map)['given'] as bool?; break; case "OneSignal#promptPermission": - this.state.calledPromptPermission = true; + state.calledPromptPermission = true; break; case "OneSignal#log": - this.state.log(call.arguments); + state.log(call.arguments); break; case "OneSignal#disablePush": - this.state.disablePush = call.arguments as bool?; + state.disablePush = call.arguments as bool?; break; case "OneSignal#postNotification": - this.state.postNotificationJson = - call.arguments as Map?; + state.postNotificationJson = call.arguments as Map?; return {"success": true}; case "OneSignal#setLocationShared": - this.state.locationShared = call.arguments as bool?; + state.locationShared = call.arguments as bool?; break; case "OneSignal#setEmail": - this.state.setEmail(call.arguments); + state.setEmail(call.arguments); break; case "OneSignal#sendTags": - this.state.tags = call.arguments; + state.tags = call.arguments; return {"success": true}; case "OneSignal#deleteTags": - this.state.deleteTags = call.arguments; + state.deleteTags = call.arguments; return {"success": true}; case "OneSignal#setExternalUserId": - this.state.externalId = (call.arguments + state.externalId = (call.arguments as Map)['externalUserId'] as String?; return {"success": true}; case "OneSignal#removeExternalUserId": - this.state.externalId = null; + state.externalId = null; return {"success": true}; case "OneSignal#setLanguage": - this.state.language = + state.language = (call.arguments as Map)['language'] as String?; return {"success": true}; } @@ -115,36 +117,36 @@ class OneSignalState { */ void setAppId(Map params) { - this.appId = params['appId']; + appId = params['appId']; } void setLogLevel(Map params) { int? level = params['logLevel'] as int?; int? visual = params['visual'] as int?; - if (level != null) this.logLevel = OSLogLevel.values[level]; - if (visual != null) this.visualLevel = OSLogLevel.values[visual]; + if (level != null) logLevel = OSLogLevel.values[level]; + if (visual != null) visualLevel = OSLogLevel.values[visual]; } void consentRequired(Map params) { - this.requiresPrivacyConsent = params['required'] as bool?; + requiresPrivacyConsent = params['required'] as bool?; } void log(Map params) { var level = params['logLevel'] as int?; - if (level != null) this.latestLogLevel = OSLogLevel.values[level]; - this.latestLogStatement = params['message']; + if (level != null) latestLogLevel = OSLogLevel.values[level]; + latestLogStatement = params['message']; } void setDisplayType(Map params) { var type = params['displayType'] as int?; if (type != null) - this.inFocusDisplayType = OSNotificationDisplayType.values[type]; + inFocusDisplayType = OSNotificationDisplayType.values[type]; } void setEmail(Map params) { - this.email = params['email'] as String?; - this.emailAuthHashToken = params['emailAuthHashToken'] as String?; + email = params['email'] as String?; + emailAuthHashToken = params['emailAuthHashToken'] as String?; } }