23 |
24 |
25 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/java/bottomnav/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/app/src/main/java/com/onesignal/spec/samples/kotlin_bottom_nav/ui/home/HomeFragment.kt:
--------------------------------------------------------------------------------
1 | package com.onesignal.spec.samples.kotlin_bottom_nav.ui.home
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import androidx.fragment.app.Fragment
9 | import androidx.lifecycle.Observer
10 | import androidx.lifecycle.ViewModelProvider
11 | import com.onesignal.spec.samples.kotlin_bottom_nav.R
12 |
13 | class HomeFragment : Fragment() {
14 |
15 | private lateinit var homeViewModel: HomeViewModel
16 |
17 | override fun onCreateView(
18 | inflater: LayoutInflater,
19 | container: ViewGroup?,
20 | savedInstanceState: Bundle?
21 | ): View? {
22 | homeViewModel =
23 | ViewModelProvider(this).get(HomeViewModel::class.java)
24 | val root = inflater.inflate(R.layout.fragment_home, container, false)
25 | val textView: TextView = root.findViewById(R.id.text_home)
26 | homeViewModel.text.observe(viewLifecycleOwner, Observer {
27 | textView.text = it
28 | })
29 | return root
30 | }
31 | }
--------------------------------------------------------------------------------
/spec/samples/googleandroid/java/bottomnav/app/src/main/res/navigation/mobile_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/app/src/main/res/navigation/mobile_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/app/src/main/java/com/onesignal/spec/samples/kotlin_bottom_nav/ui/dashboard/DashboardFragment.kt:
--------------------------------------------------------------------------------
1 | package com.onesignal.spec.samples.kotlin_bottom_nav.ui.dashboard
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import androidx.fragment.app.Fragment
9 | import androidx.lifecycle.Observer
10 | import androidx.lifecycle.ViewModelProvider
11 | import com.onesignal.spec.samples.kotlin_bottom_nav.R
12 |
13 | class DashboardFragment : Fragment() {
14 |
15 | private lateinit var dashboardViewModel: DashboardViewModel
16 |
17 | override fun onCreateView(
18 | inflater: LayoutInflater,
19 | container: ViewGroup?,
20 | savedInstanceState: Bundle?
21 | ): View? {
22 | dashboardViewModel =
23 | ViewModelProvider(this).get(DashboardViewModel::class.java)
24 | val root = inflater.inflate(R.layout.fragment_dashboard, container, false)
25 | val textView: TextView = root.findViewById(R.id.text_dashboard)
26 | dashboardViewModel.text.observe(viewLifecycleOwner, Observer {
27 | textView.text = it
28 | })
29 | return root
30 | }
31 | }
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub.
2 | # They are provided by a third-party and are governed by
3 | # separate terms of service, privacy policy, and support
4 | # documentation.
5 | # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6 | # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7 |
8 | name: Tests
9 |
10 | on:
11 | push:
12 | branches: [ main ]
13 | pull_request:
14 | branches: [ main ]
15 |
16 | permissions:
17 | contents: read
18 |
19 | jobs:
20 | test:
21 |
22 | runs-on: ubuntu-latest
23 | strategy:
24 | matrix:
25 | ruby-version: ['2.6', '2.7', '3.0']
26 |
27 | steps:
28 | - uses: actions/checkout@v3
29 | - name: Set up Ruby
30 | # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
31 | # change this to (see https://github.com/ruby/setup-ruby#versioning):
32 | # uses: ruby/setup-ruby@v1
33 | uses: ruby/setup-ruby@2b019609e2b0f1ea1a2bc8ca11cb82ab46ada124
34 | with:
35 | ruby-version: ${{ matrix.ruby-version }}
36 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically
37 | - name: Run tests
38 | run: bin/rspec spec/osproject_spec.rb
39 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/app/src/main/java/com/onesignal/spec/samples/kotlin_bottom_nav/ui/notifications/NotificationsFragment.kt:
--------------------------------------------------------------------------------
1 | package com.onesignal.spec.samples.kotlin_bottom_nav.ui.notifications
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import androidx.fragment.app.Fragment
9 | import androidx.lifecycle.Observer
10 | import androidx.lifecycle.ViewModelProvider
11 | import com.onesignal.spec.samples.kotlin_bottom_nav.R
12 |
13 | class NotificationsFragment : Fragment() {
14 |
15 | private lateinit var notificationsViewModel: NotificationsViewModel
16 |
17 | override fun onCreateView(
18 | inflater: LayoutInflater,
19 | container: ViewGroup?,
20 | savedInstanceState: Bundle?
21 | ): View? {
22 | notificationsViewModel =
23 | ViewModelProvider(this).get(NotificationsViewModel::class.java)
24 | val root = inflater.inflate(R.layout.fragment_notifications, container, false)
25 | val textView: TextView = root.findViewById(R.id.text_notifications)
26 | notificationsViewModel.text.observe(viewLifecycleOwner, Observer {
27 | textView.text = it
28 | })
29 | return root
30 | }
31 | }
--------------------------------------------------------------------------------
/DEVELOPING.md:
--------------------------------------------------------------------------------
1 | # Architecture
2 | The CLI is implemented using the Clamp framework.
3 |
4 | Controller logic for CLI commands are located in `lib/oscli.rb`. Business logic around project source code bases is located in `lib/osproject.rb` and defined in `lib/osproject_android.rb` and `lib/osproject_ios.rb`. `lib/osproject_helpers.rb` contains a suite of file manipulation functions used by OSProject subclasses.
5 |
6 | # Testing
7 |
8 | ## SDK
9 | Test cases are organized under `spec/samples`. They are organized first by platform, then language, then
10 | projectname. For example, `spec/samples/googleandroid/kotlin/bottomnav`.
11 |
12 | The primary tests are located in `spec/osproject_spec.rb`, which contains the autoloading platform test. Additional SDK sample tests are defined in this file.
13 |
14 | Using RSpec, you can run test cases using `bin/rspec spec/osproject_spec.rb`. Note that the require paths are resolved according to the dir you're in when you're executing the code so running `bin/rspec spec/osproject_spec.rb` from inside the spec folder will not work.
15 |
16 | ## CLI
17 | CLI Behavior and business logic tests are located in `spec/osproject_spec.rb`.
18 |
19 | ## API
20 | API calls are not tested, as the API Client Library codebase handles this.
21 |
22 | # Building
23 | Deliverable build process is undefined. Test via `bin/onesignal`.
24 |
--------------------------------------------------------------------------------
/.github/workflows/update_formula.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow that is manually triggered
2 |
3 | name: Update Formula
4 |
5 | # Run when a release is published to update the hombrew formula
6 | on:
7 | release:
8 | types: [released]
9 |
10 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
11 | jobs:
12 | update:
13 | # The type of runner that the job will run on
14 | runs-on: ubuntu-latest
15 |
16 | # Steps represent a sequence of tasks that will be executed as part of the job
17 | steps:
18 | - name: checkout with actions/checkout@v3
19 | uses: actions/checkout@v3
20 | with:
21 | repository: OneSignal/cli
22 | - name: run update_formula.py
23 | run: |
24 | echo ${{ github.ref_name }}
25 | echo ${{ github.sha }}
26 | python3 ./.github/workflows/update_formula.py ${{ github.ref_name }} ${{ github.sha }}
27 | - name: Commit files onesignal-cli.rb
28 | run: |
29 | git config --local user.name ${{ github.actor }}
30 | git add .
31 | git commit -m "Updating the onesignal-cli formula for the latest release"
32 | - name: Push changes # push the output folder to your repo
33 | uses: ad-m/github-push-action@master
34 | with:
35 | github_token: ${{ secrets.GITHUB_TOKEN }}
36 | force: true
37 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/app/src/main/java/com/onesignal/spec/samples/kotlin_bottom_nav/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.onesignal.spec.samples.kotlin_bottom_nav
2 |
3 | import android.os.Bundle
4 | import com.google.android.material.bottomnavigation.BottomNavigationView
5 | import androidx.appcompat.app.AppCompatActivity
6 | import androidx.navigation.findNavController
7 | import androidx.navigation.ui.AppBarConfiguration
8 | import androidx.navigation.ui.setupActionBarWithNavController
9 | import androidx.navigation.ui.setupWithNavController
10 |
11 | class MainActivity : AppCompatActivity() {
12 |
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 | setContentView(R.layout.activity_main)
16 | val navView: BottomNavigationView = findViewById(R.id.nav_view)
17 |
18 | val navController = findNavController(R.id.nav_host_fragment)
19 | // Passing each menu ID as a set of Ids because each
20 | // menu should be considered as top level destinations.
21 | val appBarConfiguration = AppBarConfiguration(setOf(
22 | R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications))
23 | setupActionBarWithNavController(navController, appBarConfiguration)
24 | navView.setupWithNavController(navController)
25 | }
26 | }
--------------------------------------------------------------------------------
/spec/samples/googleandroid/java/bottomnav/app/src/main/java/com/onesignal/spec/samples/java_bottom_nav/ui/home/HomeFragment.java:
--------------------------------------------------------------------------------
1 | package com.onesignal.spec.samples.java_bottom_nav.ui.home;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.annotation.Nullable;
11 | import androidx.fragment.app.Fragment;
12 | import androidx.lifecycle.Observer;
13 | import androidx.lifecycle.ViewModelProvider;
14 |
15 | import com.onesignal.spec.samples.java_bottom_nav.R;
16 |
17 | public class HomeFragment extends Fragment {
18 |
19 | private HomeViewModel homeViewModel;
20 |
21 | public View onCreateView(@NonNull LayoutInflater inflater,
22 | ViewGroup container, Bundle savedInstanceState) {
23 | homeViewModel =
24 | new ViewModelProvider(this).get(HomeViewModel.class);
25 | View root = inflater.inflate(R.layout.fragment_home, container, false);
26 | final TextView textView = root.findViewById(R.id.text_home);
27 | homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer() {
28 | @Override
29 | public void onChanged(@Nullable String s) {
30 | textView.setText(s);
31 | }
32 | });
33 | return root;
34 | }
35 | }
--------------------------------------------------------------------------------
/spec/samples/googleandroid/java/bottomnav/app/src/main/java/com/onesignal/spec/samples/java_bottom_nav/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.onesignal.spec.samples.java_bottom_nav;
2 |
3 | import android.os.Bundle;
4 |
5 | import com.google.android.material.bottomnavigation.BottomNavigationView;
6 |
7 | import androidx.appcompat.app.AppCompatActivity;
8 | import androidx.navigation.NavController;
9 | import androidx.navigation.Navigation;
10 | import androidx.navigation.ui.AppBarConfiguration;
11 | import androidx.navigation.ui.NavigationUI;
12 |
13 | public class MainActivity extends AppCompatActivity {
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_main);
19 | BottomNavigationView navView = findViewById(R.id.nav_view);
20 | // Passing each menu ID as a set of Ids because each
21 | // menu should be considered as top level destinations.
22 | AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
23 | R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)
24 | .build();
25 | NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
26 | NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
27 | NavigationUI.setupWithNavController(navView, navController);
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/spec/samples/googleandroid/java/bottomnav/app/src/main/java/com/onesignal/spec/samples/java_bottom_nav/ui/dashboard/DashboardFragment.java:
--------------------------------------------------------------------------------
1 | package com.onesignal.spec.samples.java_bottom_nav.ui.dashboard;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.annotation.Nullable;
11 | import androidx.fragment.app.Fragment;
12 | import androidx.lifecycle.Observer;
13 | import androidx.lifecycle.ViewModelProvider;
14 |
15 | import com.onesignal.spec.samples.java_bottom_nav.R;
16 |
17 | public class DashboardFragment extends Fragment {
18 |
19 | private DashboardViewModel dashboardViewModel;
20 |
21 | public View onCreateView(@NonNull LayoutInflater inflater,
22 | ViewGroup container, Bundle savedInstanceState) {
23 | dashboardViewModel =
24 | new ViewModelProvider(this).get(DashboardViewModel.class);
25 | View root = inflater.inflate(R.layout.fragment_dashboard, container, false);
26 | final TextView textView = root.findViewById(R.id.text_dashboard);
27 | dashboardViewModel.getText().observe(getViewLifecycleOwner(), new Observer() {
28 | @Override
29 | public void onChanged(@Nullable String s) {
30 | textView.setText(s);
31 | }
32 | });
33 | return root;
34 | }
35 | }
--------------------------------------------------------------------------------
/include/iOS/swift/NotificationService.swift:
--------------------------------------------------------------------------------
1 | import UserNotifications
2 |
3 | import OneSignal
4 |
5 | class NotificationService: UNNotificationServiceExtension {
6 |
7 | var contentHandler: ((UNNotificationContent) -> Void)?
8 | var receivedRequest: UNNotificationRequest!
9 | var bestAttemptContent: UNMutableNotificationContent?
10 |
11 | override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
12 | self.receivedRequest = request;
13 | self.contentHandler = contentHandler
14 | bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
15 |
16 | if let bestAttemptContent = bestAttemptContent {
17 | OneSignal.didReceiveNotificationExtensionRequest(self.receivedRequest, with: self.bestAttemptContent, withContentHandler: contentHandler)
18 | }
19 | }
20 |
21 | override func serviceExtensionTimeWillExpire() {
22 | // Called just before the extension will be terminated by the system.
23 | // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
24 | if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
25 | OneSignal.serviceExtensionTimeWillExpireRequest(self.receivedRequest, with: self.bestAttemptContent)
26 | contentHandler(bestAttemptContent)
27 | }
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/spec/samples/iOS/objc/ObjcExample/ObjcExample/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // ObjcExample
4 | //
5 | // Created by Elliot Mawby on 1/29/21.
6 | //
7 |
8 | #import "AppDelegate.h"
9 |
10 | @interface AppDelegate ()
11 |
12 | @end
13 |
14 | @implementation AppDelegate
15 |
16 |
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
18 | // Override point for customization after application launch.
19 | return YES;
20 | }
21 |
22 |
23 | #pragma mark - UISceneSession lifecycle
24 |
25 |
26 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
27 | // Called when a new scene session is being created.
28 | // Use this method to select a configuration to create the new scene with.
29 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
30 | }
31 |
32 |
33 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions {
34 | // Called when the user discards a scene session.
35 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
36 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
37 | }
38 |
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/java/bottomnav/app/src/main/java/com/onesignal/spec/samples/java_bottom_nav/ui/notifications/NotificationsFragment.java:
--------------------------------------------------------------------------------
1 | package com.onesignal.spec.samples.java_bottom_nav.ui.notifications;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.annotation.Nullable;
11 | import androidx.fragment.app.Fragment;
12 | import androidx.lifecycle.Observer;
13 | import androidx.lifecycle.ViewModelProvider;
14 |
15 | import com.onesignal.spec.samples.java_bottom_nav.R;
16 |
17 | public class NotificationsFragment extends Fragment {
18 |
19 | private NotificationsViewModel notificationsViewModel;
20 |
21 | public View onCreateView(@NonNull LayoutInflater inflater,
22 | ViewGroup container, Bundle savedInstanceState) {
23 | notificationsViewModel =
24 | new ViewModelProvider(this).get(NotificationsViewModel.class);
25 | View root = inflater.inflate(R.layout.fragment_notifications, container, false);
26 | final TextView textView = root.findViewById(R.id.text_notifications);
27 | notificationsViewModel.getText().observe(getViewLifecycleOwner(), new Observer() {
28 | @Override
29 | public void onChanged(@Nullable String s) {
30 | textView.setText(s);
31 | }
32 | });
33 | return root;
34 | }
35 | }
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftUIAD/SwiftUIAD/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SwiftUIAD
4 | //
5 | // Created by Elliot Mawby on 1/29/21.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 |
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | // Override point for customization after application launch.
17 | return true
18 | }
19 |
20 | // MARK: UISceneSession Lifecycle
21 |
22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
23 | // Called when a new scene session is being created.
24 | // Use this method to select a configuration to create the new scene with.
25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
26 | }
27 |
28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
29 | // Called when the user discards a scene session.
30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
32 | }
33 |
34 |
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftExample/SwiftExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SwiftExample
4 | //
5 | // Created by Elliot Mawby on 1/29/21.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 |
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | // Override point for customization after application launch.
17 | return true
18 | }
19 |
20 | // MARK: UISceneSession Lifecycle
21 |
22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
23 | // Called when a new scene session is being created.
24 | // Use this method to select a configuration to create the new scene with.
25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
26 | }
27 |
28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
29 | // Called when the user discards a scene session.
30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
32 | }
33 |
34 |
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/lib/osproject.rb:
--------------------------------------------------------------------------------
1 | class OSProject
2 | attr_reader :type
3 | attr_reader :dir
4 | attr_reader :lang
5 | attr_reader :os_app_id
6 |
7 | # Platform APIs
8 | attr_accessor :fcm_id
9 | attr_accessor :apns_id
10 |
11 | VERSION = '0.0.1'
12 | TOOL_NAME = 'onesignal-cli'
13 |
14 | def initialize(type, dir, lang, os_app_id)
15 | @type = type
16 | @dir = dir
17 | @lang = lang
18 | @os_app_id = os_app_id
19 | end
20 |
21 | # @abstract add_sdk is expected to be implemented by subclasses
22 | # @!method add_sdk!
23 | # Conduct the initial-setup process to add the latest OS SDK to the project
24 | def add_sdk!
25 | puts "type:" + self.type + " dir: " + self.dir
26 | puts "lang:" + self.lang + " os_app_id: " + self.os_app_id
27 | puts "apns_id:" + (self.apns_id || 'nil') + " fcm_id: " + (self.fcm_id || 'nil')
28 | end
29 |
30 | # @abstract has_sdk? is expected to be implemented by subclasses
31 | # @!method has_sdk?
32 | # Returns True if the project already has an SDK initialized
33 | def has_sdk?
34 | raise Exception.new "Not Implemented"
35 | end
36 |
37 | def self.os
38 | 'mac'
39 | end
40 |
41 | def self.default_command
42 | 'install-sdk'
43 | end
44 | end
45 |
46 | class OSProject::Dummy < OSProject
47 | # this is a temporary placeholder
48 | attr_accessor :has_sdk
49 |
50 | def initialize(dir, target, lang, os_app_id)
51 | @has_sdk = false
52 | super(:dummy, dir, lang, os_app_id)
53 | end
54 | def add_sdk!
55 | @has_sdk = true
56 | end
57 | def has_sdk?
58 | return self.has_sdk
59 | end
60 | end
61 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/java/bottomnav/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | }
4 |
5 | android {
6 | compileSdkVersion 30
7 | buildToolsVersion "30.0.3"
8 |
9 | defaultConfig {
10 | applicationId "com.onesignal.spec.samples.java_bottom_nav"
11 | minSdkVersion 16
12 | targetSdkVersion 30
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 | }
30 |
31 | dependencies {
32 |
33 | implementation 'androidx.appcompat:appcompat:1.2.0'
34 | implementation 'com.google.android.material:material:1.3.0'
35 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
36 | implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
37 | implementation 'androidx.navigation:navigation-fragment:2.3.3'
38 | implementation 'androidx.navigation:navigation-ui:2.3.3'
39 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
40 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
41 | testImplementation 'junit:junit:4.+'
42 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
43 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
44 | }
--------------------------------------------------------------------------------
/spec/samples/googleandroid/java/bottomnav/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
32 |
33 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
32 |
33 |
--------------------------------------------------------------------------------
/spec/samples/iOS/objc/ObjcExample/ObjcExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftExample/SwiftExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftUIAD/SwiftUIAD/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/spec/samples/iOS/objc/ObjcExample/ObjcExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftExample/SwiftExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftUIOnly/SwiftUIOnly/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 |
28 | UIApplicationSupportsIndirectInputEvents
29 |
30 | UILaunchScreen
31 |
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/lib/osproject_helpers.rb:
--------------------------------------------------------------------------------
1 | # @!method _gsub_file
2 | # Conducts a regex substition on a file. Replaces every match,
3 | # Takes either a replacement string or a block to pass to String.gsub!
4 | def _gsub_file(path, match, replace=nil, &block)
5 | content = File.read(path)
6 | if (replace == nil && block == nil) || (replace != nil && block != nil)
7 | raise
8 | elsif replace
9 | content.gsub!(match, replace)
10 | elsif block
11 | content.gsub!(match, &block)
12 | end
13 | srcfile = File.open(path, 'w')
14 | srcfile.write(content)
15 | srcfile.close
16 | end
17 |
18 | # @!method _sub_file
19 | # Conducts a regex substition on a file. Only replaces on the first match,
20 | # Takes either a replacement string or a block to pass to String.sub!
21 | def _sub_file(path, match, replace=nil, &block)
22 | content = File.read(path)
23 | result = nil
24 | if (replace == nil && block == nil) || (replace != nil && block != nil)
25 | raise
26 | elsif replace
27 | result = content.sub!(match, replace)
28 | elsif block
29 | result = content.sub!(match, &block)
30 | end
31 | srcfile = File.open(path, 'w')
32 | srcfile.write(content)
33 | srcfile.close
34 | return result
35 | end
36 |
37 | # @!method _insert_lines
38 | # Insert line, or array of lines, after a given marker. Will insert at the same indent level.
39 | def _insert_lines(file, match, insert)
40 | if insert.is_a? Array
41 | return _sub_file(file, /^(\s*)(#{match})/) do |line|
42 | indent = $1 || ''
43 | puts "indent: ", indent.length
44 | prevln = $2 || ''
45 | puts "prevln: ", prevln
46 | retline = line + "\n" + indent + insert.join("\n" + indent) + "\n"
47 | puts "retline: ", retline
48 | return retline
49 | end
50 | else
51 | return _sub_file(file, /^(\s*)(#{match})/, '\1\2' + "\n" + '\1' + insert)
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/java/bottomnav/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | }
5 |
6 | android {
7 | compileSdkVersion 30
8 | buildToolsVersion "30.0.3"
9 |
10 | defaultConfig {
11 | applicationId "com.onesignal.spec.samples.kotlin_bottom_nav"
12 | minSdkVersion 16
13 | targetSdkVersion 30
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | kotlinOptions {
31 | jvmTarget = '1.8'
32 | }
33 | }
34 |
35 | dependencies {
36 |
37 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
38 | implementation 'androidx.core:core-ktx:1.3.2'
39 | implementation 'androidx.appcompat:appcompat:1.2.0'
40 | implementation 'com.google.android.material:material:1.2.1'
41 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
42 | implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
43 | implementation 'androidx.navigation:navigation-fragment:2.2.2'
44 | implementation 'androidx.navigation:navigation-ui:2.2.2'
45 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
46 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
47 | implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
48 | implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
49 | testImplementation 'junit:junit:4.+'
50 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
51 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
52 | }
--------------------------------------------------------------------------------
/include/iOS/objc/NotificationService.m:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | #import "NotificationService.h"
4 |
5 | @interface NotificationService ()
6 |
7 | @property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
8 | @property (nonatomic, strong) UNNotificationRequest *receivedRequest;
9 | @property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
10 |
11 | @end
12 |
13 | @implementation NotificationService
14 |
15 | - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
16 | self.receivedRequest = request;
17 | self.contentHandler = contentHandler;
18 | self.bestAttemptContent = [request.content mutableCopy];
19 |
20 | // DEBUGGING: Uncomment the 2 lines below and comment out the one above to ensure this extension is excuting
21 | // Note, this extension only runs when mutable-content is set
22 | // Setting an attachment or action buttons automatically adds this
23 | // NSLog(@"Running NotificationServiceExtension");
24 | // self.bestAttemptContent.body = [@"[Modified] " stringByAppendingString:self.bestAttemptContent.body];
25 |
26 | // Uncomment this line to set the default log level of NSE to VERBOSE so we get all logs from NSE logic
27 | //[OneSignal setLogLevel:ONE_S_LL_VERBOSE visualLevel:ONE_S_LL_NONE];
28 |
29 | [OneSignal didReceiveNotificationExtensionRequest:self.receivedRequest withMutableNotificationContent:self.bestAttemptContent withContentHandler:self.contentHandler];
30 | }
31 |
32 | - (void)serviceExtensionTimeWillExpire {
33 | // Called just before the extension will be terminated by the system.
34 | // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
35 |
36 | [OneSignal serviceExtensionTimeWillExpireRequest:self.receivedRequest withMutableNotificationContent:self.bestAttemptContent];
37 |
38 | self.contentHandler(self.bestAttemptContent);
39 | }
40 |
41 | @end
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftUIAD/SwiftUIAD/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/spec/samples/iOS/objc/ObjcExample/ObjcExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftUIOnly/SwiftUIOnly/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftExample/SwiftExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftUIAD/SwiftUIAD/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UIApplicationSupportsIndirectInputEvents
41 |
42 | UILaunchStoryboardName
43 | LaunchScreen
44 | UIRequiredDeviceCapabilities
45 |
46 | armv7
47 |
48 | UISupportedInterfaceOrientations
49 |
50 | UIInterfaceOrientationPortrait
51 | UIInterfaceOrientationLandscapeLeft
52 | UIInterfaceOrientationLandscapeRight
53 |
54 | UISupportedInterfaceOrientations~ipad
55 |
56 | UIInterfaceOrientationPortrait
57 | UIInterfaceOrientationPortraitUpsideDown
58 | UIInterfaceOrientationLandscapeLeft
59 | UIInterfaceOrientationLandscapeRight
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/spec/samples/iOS/objc/ObjcExample/ObjcExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | SceneDelegate
36 | UISceneStoryboardFile
37 | Main
38 |
39 |
40 |
41 |
42 | UIApplicationSupportsIndirectInputEvents
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIMainStoryboardFile
47 | Main
48 | UIRequiredDeviceCapabilities
49 |
50 | armv7
51 |
52 | UISupportedInterfaceOrientations
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationLandscapeLeft
56 | UIInterfaceOrientationLandscapeRight
57 |
58 | UISupportedInterfaceOrientations~ipad
59 |
60 | UIInterfaceOrientationPortrait
61 | UIInterfaceOrientationPortraitUpsideDown
62 | UIInterfaceOrientationLandscapeLeft
63 | UIInterfaceOrientationLandscapeRight
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftExample/SwiftExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 | UISceneStoryboardFile
37 | Main
38 |
39 |
40 |
41 |
42 | UIApplicationSupportsIndirectInputEvents
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIMainStoryboardFile
47 | Main
48 | UIRequiredDeviceCapabilities
49 |
50 | armv7
51 |
52 | UISupportedInterfaceOrientations
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationLandscapeLeft
56 | UIInterfaceOrientationLandscapeRight
57 |
58 | UISupportedInterfaceOrientations~ipad
59 |
60 | UIInterfaceOrientationPortrait
61 | UIInterfaceOrientationPortraitUpsideDown
62 | UIInterfaceOrientationLandscapeLeft
63 | UIInterfaceOrientationLandscapeRight
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/spec/samples/iOS/objc/ObjcExample/ObjcExample/SceneDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.m
3 | // ObjcExample
4 | //
5 | // Created by Elliot Mawby on 1/29/21.
6 | //
7 |
8 | #import "SceneDelegate.h"
9 |
10 | @interface SceneDelegate ()
11 |
12 | @end
13 |
14 | @implementation SceneDelegate
15 |
16 |
17 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
18 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
19 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
20 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
21 | }
22 |
23 |
24 | - (void)sceneDidDisconnect:(UIScene *)scene {
25 | // Called as the scene is being released by the system.
26 | // This occurs shortly after the scene enters the background, or when its session is discarded.
27 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
28 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
29 | }
30 |
31 |
32 | - (void)sceneDidBecomeActive:(UIScene *)scene {
33 | // Called when the scene has moved from an inactive state to an active state.
34 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
35 | }
36 |
37 |
38 | - (void)sceneWillResignActive:(UIScene *)scene {
39 | // Called when the scene will move from an active state to an inactive state.
40 | // This may occur due to temporary interruptions (ex. an incoming phone call).
41 | }
42 |
43 |
44 | - (void)sceneWillEnterForeground:(UIScene *)scene {
45 | // Called as the scene transitions from the background to the foreground.
46 | // Use this method to undo the changes made on entering the background.
47 | }
48 |
49 |
50 | - (void)sceneDidEnterBackground:(UIScene *)scene {
51 | // Called as the scene transitions from the foreground to the background.
52 | // Use this method to save data, release shared resources, and store enough scene-specific state information
53 | // to restore the scene back to its current state.
54 | }
55 |
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/lib/osnetwork.rb:
--------------------------------------------------------------------------------
1 | require 'clamp'
2 | require 'net/http'
3 | require_relative 'osproject'
4 | require_relative 'osproject_ios'
5 | require_relative 'osproject_android'
6 |
7 | class NetworkHandler
8 | @instance = new
9 |
10 | private_class_method :new
11 |
12 | URL = 'https://api.onesignal.com/api/v1/track'
13 |
14 | def self.instance
15 | @instance
16 | end
17 |
18 | def get_http_net()
19 | uri = URI.parse(URL)
20 | http = Net::HTTP.new(uri.host, uri.port)
21 | http.use_ssl = true
22 | http
23 | end
24 |
25 | def send_track_error(app_id:, platform:, lang:, error_message:)
26 | send_track_command_actions(app_id: app_id, platform: platform, lang: lang, command: OSProject.default_command, error_message: error_message)
27 | end
28 |
29 | def send_track_actions(app_id:, platform:, lang:, actions_taken:)
30 | send_track_command_actions(app_id: app_id, platform: platform, lang: lang, command: OSProject.default_command, actions_taken: actions_taken)
31 | end
32 |
33 | # Send command used by the user for tracking
34 | # There are cases where --help, --version commands might be used, and there is no other data in addition to the command name
35 | def send_track_command(command)
36 | http = get_http_net()
37 |
38 | request = Net::HTTP::Post.new(URL)
39 |
40 | request['app_id'] = ""
41 | request['OS-Usage-Data'] = get_usage_data(command: command)
42 |
43 | response = http.request(request)
44 | end
45 |
46 | private
47 |
48 | def send_track_command_actions(app_id:, platform:nil, lang:nil, command:nil, actions_taken:nil, error_message:nil)
49 | http = get_http_net()
50 |
51 | request = Net::HTTP::Post.new(URL)
52 |
53 | request['app_id'] = app_id
54 | request['OS-Usage-Data'] = get_usage_data(platform: platform, lang: lang, command: command, actions_taken: actions_taken, error_message: error_message)
55 |
56 | response = http.request(request)
57 | end
58 |
59 | def get_usage_data(platform:nil, lang:nil, command:nil, actions_taken:nil, error_message:nil)
60 | data = "kind=sdk, sdk-name=#{OSProject::TOOL_NAME}, version=#{OSProject::VERSION}, target-os=#{OSProject.os}"
61 |
62 | data += ", type=#{platform}" if platform
63 | data += ", lang=#{lang}" if lang
64 | data += ", command=#{command}" if command
65 | data += ", actions=#{actions_taken}" if actions_taken
66 | data += ", error=#{error_message}" if error_message
67 |
68 | return data
69 | end
70 | end
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftExample/SwiftExample/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // SwiftExample
4 | //
5 | // Created by Elliot Mawby on 1/29/21.
6 | //
7 |
8 | import UIKit
9 |
10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
11 |
12 | var window: UIWindow?
13 |
14 |
15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
19 | guard let _ = (scene as? UIWindowScene) else { return }
20 | }
21 |
22 | func sceneDidDisconnect(_ scene: UIScene) {
23 | // Called as the scene is being released by the system.
24 | // This occurs shortly after the scene enters the background, or when its session is discarded.
25 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
27 | }
28 |
29 | func sceneDidBecomeActive(_ scene: UIScene) {
30 | // Called when the scene has moved from an inactive state to an active state.
31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
32 | }
33 |
34 | func sceneWillResignActive(_ scene: UIScene) {
35 | // Called when the scene will move from an active state to an inactive state.
36 | // This may occur due to temporary interruptions (ex. an incoming phone call).
37 | }
38 |
39 | func sceneWillEnterForeground(_ scene: UIScene) {
40 | // Called as the scene transitions from the background to the foreground.
41 | // Use this method to undo the changes made on entering the background.
42 | }
43 |
44 | func sceneDidEnterBackground(_ scene: UIScene) {
45 | // Called as the scene transitions from the foreground to the background.
46 | // Use this method to save data, release shared resources, and store enough scene-specific state information
47 | // to restore the scene back to its current state.
48 | }
49 |
50 |
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/java/bottomnav/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/spec/samples/iOS/swift/SwiftUIAD/SwiftUIAD/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // SwiftUIAD
4 | //
5 | // Created by Elliot Mawby on 1/29/21.
6 | //
7 |
8 | import UIKit
9 | import SwiftUI
10 |
11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
12 |
13 | var window: UIWindow?
14 |
15 |
16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
20 |
21 | // Create the SwiftUI view that provides the window contents.
22 | let contentView = ContentView()
23 |
24 | // Use a UIHostingController as window root view controller.
25 | if let windowScene = scene as? UIWindowScene {
26 | let window = UIWindow(windowScene: windowScene)
27 | window.rootViewController = UIHostingController(rootView: contentView)
28 | self.window = window
29 | window.makeKeyAndVisible()
30 | }
31 | }
32 |
33 | func sceneDidDisconnect(_ scene: UIScene) {
34 | // Called as the scene is being released by the system.
35 | // This occurs shortly after the scene enters the background, or when its session is discarded.
36 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
37 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
38 | }
39 |
40 | func sceneDidBecomeActive(_ scene: UIScene) {
41 | // Called when the scene has moved from an inactive state to an active state.
42 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
43 | }
44 |
45 | func sceneWillResignActive(_ scene: UIScene) {
46 | // Called when the scene will move from an active state to an inactive state.
47 | // This may occur due to temporary interruptions (ex. an incoming phone call).
48 | }
49 |
50 | func sceneWillEnterForeground(_ scene: UIScene) {
51 | // Called as the scene transitions from the background to the foreground.
52 | // Use this method to undo the changes made on entering the background.
53 | }
54 |
55 | func sceneDidEnterBackground(_ scene: UIScene) {
56 | // Called as the scene transitions from the foreground to the background.
57 | // Use this method to save data, release shared resources, and store enough scene-specific state information
58 | // to restore the scene back to its current state.
59 | }
60 |
61 |
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OneSignal CLI
2 |
3 | ### :warning: This tool is currently in [Beta](https://github.com/OneSignal/cli/issues/5) :warning:
4 |
5 | The OneSignal CLI is a tool to work with OneSignal projects.
6 |
7 | # Mac Setup
8 | 1. Have Homebrew installed
9 | 2. Run `brew tap OneSignal/cli https://github.com/OneSignal/cli`
10 | 3. Run `brew install onesignal-cli`
11 |
12 | ## Available commands
13 |
14 | * `onesignal help` Lists the available commands in the OneSignal CLI
15 | * `onesignal install-sdk` Install the OneSignal SDK in the project
16 |
17 | ## Installation Command
18 | This command can be used to add the OneSignal SDK to your mobile application project.
19 | Currently only supports iOS and Android Native SDK install.
20 |
21 | For iOS the command will:
22 | * Add push notification capabilities and background modes
23 | * Add the OneSignal cocoapod or Swift Package
24 | * Create and setup a Notification Service Extension
25 | * Setup an App Group for communication with the NSE.
26 |
27 | Note that this command does not yet add initialization code to your app so please follow [step 5 of the guide](https://documentation.onesignal.com/docs/ios-sdk-setup#step-5---add-the-onesignal-initialization-code) to complete installation.
28 |
29 | For Android the command will:
30 | * Add the OneSignal gradle dependencies under project and app build.gradle file
31 | * Add the OneSignal initialization code under Application Class. If no application class is available, the CLI tool will create it for you at the given path.
32 |
33 | Note: Re sync gradle might be needed after calling install-sdk
34 |
35 | Options:
36 | * type - iOS or Android. Type of SDK to install. Required.
37 | * target - name of the App target to install in. Defaults to the entrypoint name. iOS only.
38 |
39 | Arguments:
40 | * Entrypoint - Name of the target XCProject (iOS) or Application class file directory (Android). For Android, if no application class is available, the CLI will create it in the directory and name file provided. For the CLI to create the file for you, you will need to provide the directory inside the project and file name with the extension where you want the Application file to be created. Example: app/src/main/java/com/onesignal/testapplication/BaseApp.java
41 | * LANG - programming language to use for ios (objc, swift) or Android (java, kotlin)
42 | * APPID - Optional. OneSignal App ID. Not yet used for iOS installs.
43 | * TARGET - Optional. Used for the iOS install if your App target name is different from the entrypoint name
44 |
45 | Example Usage, run the following command on the root project directory where OneSignal SDK is going to be use
46 | * iOS: `onesignal install-sdk --type iOS --entrypoint MyApp --lang objc --appid `
47 | * Android: `onesignal install-sdk --type android --entrypoint app/src/main/java/com/onesignal/testapplication/BaseApp.kt --appid `
48 |
49 | ## Limitations / Comming Soon
50 | * React Native, Flutter, Unity, Xamarin, and Cordova aren't currently supported. Stay tuned for support in a future release!
51 | * macOS is currently the only officially supported operating system.
52 |
--------------------------------------------------------------------------------
/spec/osproject_helpers_spec.rb:
--------------------------------------------------------------------------------
1 | require 'osproject_helpers'
2 |
3 | RSpec.describe "_sub_file" do
4 | it "successfully subsitutes first match with string" do
5 | contents = File.read('spec/samplefile.txt')
6 | expect(contents.scan(/foo/).length).to eq 4
7 | expect(contents.scan(/fbb/).length).to eq 0
8 | _sub_file('spec/samplefile.txt', 'foo', 'fbb')
9 | contents = File.read('spec/samplefile.txt')
10 | expect(contents.scan(/foo/).length).to eq 3
11 | expect(contents.scan(/fbb/).length).to eq 1
12 | _sub_file('spec/samplefile.txt', 'fbb', 'foo')
13 | contents = File.read('spec/samplefile.txt')
14 | expect(contents.scan(/foo/).length).to eq 4
15 | expect(contents.scan(/fbb/).length).to eq 0
16 | end
17 | it "successfully subsitutes first match with block" do
18 | contents = File.read('spec/samplefile.txt')
19 | expect(contents.scan(/foo/).length).to eq 4
20 | expect(contents.scan(/fbb/).length).to eq 0
21 | _sub_file('spec/samplefile.txt', 'foo') do |line|
22 | "fbb"
23 | end
24 | contents = File.read('spec/samplefile.txt')
25 | expect(contents.scan(/foo/).length).to eq 3
26 | expect(contents.scan(/fbb/).length).to eq 1
27 | _sub_file('spec/samplefile.txt', 'fbb') do |line|
28 | "foo"
29 | end
30 | contents = File.read('spec/samplefile.txt')
31 | expect(contents.scan(/foo/).length).to eq 4
32 | expect(contents.scan(/fbb/).length).to eq 0
33 | end
34 | end
35 |
36 | RSpec.describe "_gsub_file" do
37 | it "successfully subsitutes matches with string" do
38 | contents = File.read('spec/samplefile.txt')
39 | puts(contents.count('foo'))
40 | expect(contents.scan(/foo/).length).to eq 4
41 | expect(contents.scan(/fbb/).length).to eq 0
42 | _gsub_file('spec/samplefile.txt', 'foo', 'fbb')
43 | contents = File.read('spec/samplefile.txt')
44 | expect(contents.scan(/foo/).length).to eq 0
45 | expect(contents.scan(/fbb/).length).to eq 4
46 | _gsub_file('spec/samplefile.txt', 'fbb', 'foo')
47 | contents = File.read('spec/samplefile.txt')
48 | expect(contents.scan(/foo/).length).to eq 4
49 | expect(contents.scan(/fbb/).length).to eq 0
50 | end
51 | it "successfully subsitutes matches with block" do
52 | contents = File.read('spec/samplefile.txt')
53 | puts(contents.count('foo'))
54 | expect(contents.scan(/foo/).length).to eq 4
55 | expect(contents.scan(/fbb/).length).to eq 0
56 | _gsub_file('spec/samplefile.txt', 'foo') do |line|
57 | "fbb"
58 | end
59 | contents = File.read('spec/samplefile.txt')
60 | expect(contents.scan(/foo/).length).to eq 0
61 | expect(contents.scan(/fbb/).length).to eq 4
62 | _gsub_file('spec/samplefile.txt', 'fbb') do |line|
63 | "foo"
64 | end
65 | contents = File.read('spec/samplefile.txt')
66 | expect(contents.scan(/foo/).length).to eq 4
67 | expect(contents.scan(/fbb/).length).to eq 0
68 | end
69 | end
70 |
71 | RSpec.describe "_insert_lines" do
72 | it "successfully inserts line after marker" do
73 | end
74 | it "successfully inserts lines after marker" do
75 | end
76 | end
77 |
--------------------------------------------------------------------------------
/spec/osproject_spec.rb:
--------------------------------------------------------------------------------
1 | require 'osproject'
2 | require 'osproject_android'
3 | require 'osproject_ios'
4 | require 'tmpdir'
5 |
6 | sdkmap = {
7 | 'googleandroid' => OSProject::GoogleAndroid,
8 | 'iOS' => OSProject::IOS,
9 | }
10 |
11 | Dir.foreach("spec/samples") do |platform|
12 | next if platform == '..' or platform == '.' or platform.include? "."
13 | proj_class = sdkmap[platform]
14 | Dir.foreach("spec/samples/" + platform) do |lang|
15 | next if lang == '..' or lang == '.' or lang.include? "."
16 | Dir.foreach("spec/samples/" + platform + '/' + lang) do |sampledirname|
17 | next if sampledirname == '..' or sampledirname == '.' or sampledirname.include? "."
18 | sampledir = 'spec/samples/' + platform + '/' + lang + '/' + sampledirname
19 | tmpdir = Dir.mktmpdir()
20 | projdir = tmpdir + '/' + sampledirname
21 | RSpec.describe OSProject, ".add_sdk" do
22 | before(:all) do
23 | FileUtils.cp_r(sampledir, projdir, verbose: true)
24 | end
25 | after(:all) do
26 | FileUtils.remove_entry tmpdir
27 | end
28 | context sampledirname do
29 | it "successfully instantitates the object" do
30 | if platform == 'googleandroid'
31 | langextension =
32 | if lang == 'kotlin'
33 | 'kt'
34 | else
35 | lang
36 | end
37 | appclasspath = 'app/src/main/'+lang+'/com/onesignal/spec/samples/'+lang+'_bottom_nav/ApplicationClass.'+langextension
38 | proj = proj_class.new(appclasspath, 'app_id', projdir)
39 | elsif platform =='iOS'
40 | proj = proj_class.new(projdir, 'targetname', lang, 'app_id')
41 | expect(proj.type.to_s).to eq platform
42 | expect(proj.dir).to eq projdir
43 | end
44 | end
45 | it "successfully adds sdk" do
46 | if platform == 'googleandroid'
47 | langextension =
48 | if lang == 'kotlin'
49 | 'kt'
50 | else
51 | lang
52 | end
53 | # For Android samples, we have a appclassfile symlink in the proj root dir
54 | # When users use the CLI, they specify the file.
55 | appclasspath = 'app/src/main/java/com/onesignal/spec/samples/'+lang+'_bottom_nav/ApplicationClass.'+langextension
56 | proj = proj_class.new(appclasspath, 'app_id', projdir)
57 | expect(proj.has_sdk?()).to eq false
58 | proj.add_sdk!()
59 | expect(proj.has_sdk?()).to eq true
60 | elsif platform =='iOS'
61 | proj = proj_class.new(projdir, sampledirname, lang, 'app_id')
62 | xcodeproj_path = projdir + '/' + sampledirname + '.xcodeproj'
63 | expect(proj.has_sdk?()).to eq false
64 | proj.install_onesignal!(xcodeproj_path)
65 | expect(proj.has_sdk?()).to eq true
66 | end
67 |
68 | end
69 | end
70 | end
71 | end
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | #
5 | # This file was generated by Bundler.
6 | #
7 | # The application 'bundle' is installed as part of a gem, and
8 | # this file is here to facilitate running it.
9 | #
10 |
11 | require "rubygems"
12 |
13 | m = Module.new do
14 | module_function
15 |
16 | def invoked_as_script?
17 | File.expand_path($0) == File.expand_path(__FILE__)
18 | end
19 |
20 | def env_var_version
21 | ENV["BUNDLER_VERSION"]
22 | end
23 |
24 | def cli_arg_version
25 | return unless invoked_as_script? # don't want to hijack other binstubs
26 | return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27 | bundler_version = nil
28 | update_index = nil
29 | ARGV.each_with_index do |a, i|
30 | if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31 | bundler_version = a
32 | end
33 | next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34 | bundler_version = $1
35 | update_index = i
36 | end
37 | bundler_version
38 | end
39 |
40 | def gemfile
41 | gemfile = ENV["BUNDLE_GEMFILE"]
42 | return gemfile if gemfile && !gemfile.empty?
43 |
44 | File.expand_path("../../Gemfile", __FILE__)
45 | end
46 |
47 | def lockfile
48 | lockfile =
49 | case File.basename(gemfile)
50 | when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51 | else "#{gemfile}.lock"
52 | end
53 | File.expand_path(lockfile)
54 | end
55 |
56 | def lockfile_version
57 | return unless File.file?(lockfile)
58 | lockfile_contents = File.read(lockfile)
59 | return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60 | Regexp.last_match(1)
61 | end
62 |
63 | def bundler_version
64 | @bundler_version ||=
65 | env_var_version || cli_arg_version ||
66 | lockfile_version
67 | end
68 |
69 | def bundler_requirement
70 | return "#{Gem::Requirement.default}.a" unless bundler_version
71 |
72 | bundler_gem_version = Gem::Version.new(bundler_version)
73 |
74 | requirement = bundler_gem_version.approximate_recommendation
75 |
76 | return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0")
77 |
78 | requirement += ".a" if bundler_gem_version.prerelease?
79 |
80 | requirement
81 | end
82 |
83 | def load_bundler!
84 | ENV["BUNDLE_GEMFILE"] ||= gemfile
85 |
86 | activate_bundler
87 | end
88 |
89 | def activate_bundler
90 | gem_error = activation_error_handling do
91 | gem "bundler", bundler_requirement
92 | end
93 | return if gem_error.nil?
94 | require_error = activation_error_handling do
95 | require "bundler/version"
96 | end
97 | return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
98 | warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
99 | exit 42
100 | end
101 |
102 | def activation_error_handling
103 | yield
104 | nil
105 | rescue StandardError, LoadError => e
106 | e
107 | end
108 | end
109 |
110 | m.load_bundler!
111 |
112 | if m.invoked_as_script?
113 | load Gem.bin_path("bundler", "bundle")
114 | end
115 |
--------------------------------------------------------------------------------
/lib/oscli.rb:
--------------------------------------------------------------------------------
1 | require 'clamp'
2 | require_relative 'osproject'
3 | require_relative 'osproject_ios'
4 | require_relative 'osproject_android'
5 | require 'net/http'
6 | require 'uri'
7 | require 'resolv-replace'
8 |
9 | class InstallCommand < Clamp::Command
10 | option [ "-t", "--type"], "TYPE", "project type (ios, android)"
11 | option ["--target"], "TARGETNAME", "name of the App target to use. Defaults to the entrypoint name"
12 | option ["--entrypoint"], "ENTRYPOINT", "Name of the target XCProject (ios) or appclassfile (android)"
13 | option ["--lang"], "LANG", "programming language to use for ios (objc, swift) or android (java, kotlin)"
14 | option ["--appid"], "[APPID]", "OneSignal App ID"
15 |
16 | def execute
17 | if appid.nil? || appid.empty?
18 | puts 'Please provide a project appId with the --appid option'
19 | error_track_message = "User missed --appId param"
20 | NetworkHandler.instance.send_track_error(app_id: "", platform: type, lang: lang, error_message: error_track_message)
21 | exit(1)
22 | end
23 |
24 | if !type
25 | puts 'Please provide a project type (ios or android) with the --type option'
26 | error_track_message = "User missed --type param"
27 | NetworkHandler.instance.send_track_error(app_id: "", platform: type, lang: lang, error_message: error_track_message)
28 | exit(1)
29 | end
30 |
31 | type_downcase = type.downcase
32 | if type_downcase == 'ios'
33 | langmap = {
34 | 'objc' => :objc,
35 | 'swift' => :swift
36 | }
37 | language = langmap[lang]
38 |
39 | unless language == :objc || language == :swift
40 | puts 'Invalid language (objc or swift)'
41 | error_track_message = "User provide invalid language"
42 | NetworkHandler.instance.send_track_error(app_id: "", platform: type, lang: lang, error_message: error_track_message)
43 | exit(1)
44 | end
45 | targetname = target
46 | if !targetname
47 | targetname = entrypoint
48 | end
49 | dir = ''
50 | if entrypoint.include? '/'
51 | dir = entrypoint.slice(0, entrypoint.rindex('/')) # => "/path/to"
52 | end
53 | path = Dir.pwd + '/' + dir
54 | ios_proj = OSProject::IOS.new(path, targetname, language, appid)
55 | xcodeproj_path = Dir.pwd + '/' + entrypoint + '.xcodeproj'
56 | ios_proj.install_onesignal!(xcodeproj_path)
57 | elsif type_downcase == 'android'
58 | dir = Dir.pwd
59 | OSProject::GoogleAndroid.new(entrypoint, appid, dir).add_sdk!()
60 | else
61 | puts 'Invalid type (ios or android)'
62 | error_track_message = "User provide invalid type: #{type}"
63 | NetworkHandler.instance.send_track_error(app_id: "", platform: type, lang: lang, error_message: error_track_message)
64 | end
65 |
66 | end
67 | end
68 |
69 | class MooCommand < Clamp::Command
70 | def execute
71 | puts <<~COW
72 | _____________________
73 | < Moooooooooooooooooo >
74 | ---------------------
75 | \\ ^__^
76 | \\ (oo)\\_______
77 | (__)\\ )\\/\\
78 | ||----w |
79 | || ||
80 | COW
81 | end
82 | end
83 |
84 | class HelpCommand < Clamp::Command
85 | def execute
86 | OSCLI.helptext
87 | end
88 | end
89 |
90 | class AvailableCommandsCommand < Clamp::Command
91 | def execute
92 | OSCLI.availableCommandsText
93 | end
94 | end
95 |
96 | class OSCLI < Clamp::Command
97 | option ["--version", "-v"], :flag, "Show version" do
98 | puts OSProject::VERSION
99 | NetworkHandler.instance.send_track_command("--version")
100 | exit(0)
101 | end
102 | option ["--help", "-h"], :flag, "Show Commands" do
103 | OSCLI.helptext
104 | exit(0)
105 | end
106 | self.default_subcommand = "available-commands"
107 | subcommand "available-commands", "Lists the available commands in the OneSignal CLI", AvailableCommandsCommand
108 | subcommand "help", "Lists the available commands in the OneSignal CLI", HelpCommand
109 | subcommand "install-sdk", "Add the OneSignal SDK to the project", InstallCommand
110 |
111 | def self.helptext
112 | puts "usage: onesignal [--version] [--help] [install-sdk --type --entrypoint --lang --appid ]"
113 | NetworkHandler.instance.send_track_command("--help")
114 | end
115 |
116 | def self.availableCommandsText
117 | puts <<~HELP
118 | \e[1mAvailable Commands:\e[0m
119 | \e[1minstall-sdk:\e[0m Install the OneSignal SDK in the project
120 | \e[1mhelp:\e[0m Lists the available commands in the OneSignal CLI
121 | See: --help for details
122 | HELP
123 | NetworkHandler.instance.send_track_command("available-commands")
124 | end
125 | end
126 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # This file was generated by the `rspec --init` command. Conventionally, all
2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3 | # The generated `.rspec` file contains `--require spec_helper` which will cause
4 | # this file to always be loaded, without a need to explicitly require it in any
5 | # files.
6 | #
7 | # Given that it is always loaded, you are encouraged to keep this file as
8 | # light-weight as possible. Requiring heavyweight dependencies from this file
9 | # will add to the boot time of your test suite on EVERY test run, even for an
10 | # individual file that may not need all of that loaded. Instead, consider making
11 | # a separate helper file that requires the additional dependencies and performs
12 | # the additional setup, and require it from the spec files that actually need
13 | # it.
14 | #
15 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16 | RSpec.configure do |config|
17 | # rspec-expectations config goes here. You can use an alternate
18 | # assertion/expectation library such as wrong or the stdlib/minitest
19 | # assertions if you prefer.
20 | config.expect_with :rspec do |expectations|
21 | # This option will default to `true` in RSpec 4. It makes the `description`
22 | # and `failure_message` of custom matchers include text for helper methods
23 | # defined using `chain`, e.g.:
24 | # be_bigger_than(2).and_smaller_than(4).description
25 | # # => "be bigger than 2 and smaller than 4"
26 | # ...rather than:
27 | # # => "be bigger than 2"
28 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
29 | end
30 |
31 | # rspec-mocks config goes here. You can use an alternate test double
32 | # library (such as bogus or mocha) by changing the `mock_with` option here.
33 | config.mock_with :rspec do |mocks|
34 | # Prevents you from mocking or stubbing a method that does not exist on
35 | # a real object. This is generally recommended, and will default to
36 | # `true` in RSpec 4.
37 | mocks.verify_partial_doubles = true
38 | end
39 |
40 | # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
41 | # have no way to turn it off -- the option exists only for backwards
42 | # compatibility in RSpec 3). It causes shared context metadata to be
43 | # inherited by the metadata hash of host groups and examples, rather than
44 | # triggering implicit auto-inclusion in groups with matching metadata.
45 | config.shared_context_metadata_behavior = :apply_to_host_groups
46 |
47 | # The settings below are suggested to provide a good initial experience
48 | # with RSpec, but feel free to customize to your heart's content.
49 | =begin
50 | # This allows you to limit a spec run to individual examples or groups
51 | # you care about by tagging them with `:focus` metadata. When nothing
52 | # is tagged with `:focus`, all examples get run. RSpec also provides
53 | # aliases for `it`, `describe`, and `context` that include `:focus`
54 | # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
55 | config.filter_run_when_matching :focus
56 |
57 | # Allows RSpec to persist some state between runs in order to support
58 | # the `--only-failures` and `--next-failure` CLI options. We recommend
59 | # you configure your source control system to ignore this file.
60 | config.example_status_persistence_file_path = "spec/examples.txt"
61 |
62 | # Limits the available syntax to the non-monkey patched syntax that is
63 | # recommended. For more details, see:
64 | # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
65 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
66 | # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
67 | config.disable_monkey_patching!
68 |
69 | # This setting enables warnings. It's recommended, but in some cases may
70 | # be too noisy due to issues in dependencies.
71 | config.warnings = true
72 |
73 | # Many RSpec users commonly either run the entire suite or an individual
74 | # file, and it's useful to allow more verbose output when running an
75 | # individual spec file.
76 | if config.files_to_run.one?
77 | # Use the documentation formatter for detailed output,
78 | # unless a formatter has already been configured
79 | # (e.g. via a command-line flag).
80 | config.default_formatter = "doc"
81 | end
82 |
83 | # Print the 10 slowest examples and example groups at the
84 | # end of the spec run, to help surface which specs are running
85 | # particularly slow.
86 | config.profile_examples = 10
87 |
88 | # Run specs in random order to surface order dependencies. If you find an
89 | # order dependency and want to debug it, you can fix the order by providing
90 | # the seed, which is printed after each run.
91 | # --seed 1234
92 | config.order = :random
93 |
94 | # Seed global randomization in this process using the `--seed` CLI option.
95 | # Setting this allows you to use `--seed` to deterministically reproduce
96 | # test failures related to randomization by passing the same `--seed` value
97 | # as the one that triggered the failure.
98 | Kernel.srand config.seed
99 | =end
100 | end
101 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/java/bottomnav/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/java/bottomnav/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/spec/samples/googleandroid/kotlin/bottomnav/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------