diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index ac07159..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## [0.0.1] - TODO: Add release date. - -* TODO: Describe initial release. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index ba75c69..0000000 --- a/LICENSE +++ /dev/null @@ -1 +0,0 @@ -TODO: Add your license here. diff --git a/README.md b/README.md index f76adae..427982a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,59 @@ -# appcenter +# Visual Studio App Center Plugin for Flutter -A new flutter plugin project. +[![pub package](https://img.shields.io/pub/v/appcenter.svg)](https://pub.dartlang.org/packages/appcenter) + +Several Flutter plugins to use the [Microsoft Visual Studio App Center SDKs](https://docs.microsoft.com/en-us/appcenter/sdk/). + +*Note*: This plugin is still under development, and some APIs (*Distribute* and *Push* are still missing) might not be available yet. [Feedback](https://github.com/aloisdeniel/flutter_plugin_appcenter/issues) and [Pull Requests](https://github.com/aloisdeniel/flutter_plugin_appcenter/pulls) are most welcome! + +## Setup + +To use this plugin: + +1. Connect to [Visual Studio App Center Portal](https://appcenter.ms/apps) +1. From the index page, select `Add new` and create a new **iOS application (Platform: Objective-C/Swift)**, and keep your iOS app secret (ex: `123cfac9-123b-123a-123f-123273416a48`). +1. From the index page, select `Add new` and create a new **Android application (Platform: Java)**, and keep your Android app secret (ex: `321cfac9-123b-123a-123f-123273416a48`). +1. Add those as [dependencies in your pubspec.yaml file](https://flutter.io/platform-plugins/): + * `appcenter` + * `appcenter_analytics` + * `appcenter_crashes` + +## Usage + +### Global + +```dart +import 'package:appcenter/appcenter.dart'; +import 'package:appcenter_analytics/appcenter_analytics.dart'; +import 'package:appcenter_crashes/appcenter_crashes.dart'; +``` + +#### Starting services + +```dart +final ios = defaultTargetPlatform == TargetPlatform.iOS; +var app_secret = ios ? "123cfac9-123b-123a-123f-123273416a48" : "321cfac9-123b-123a-123f-123273416a48"; + +await AppCenter.start(app_secret, [AppCenterAnalytics.id, AppCenterCrashes.id]); +``` + +#### Enabling or disabling services + +```dart +await AppCenter.setEnabled(false); // global +await AppCenterAnalytics.setEnabled(false); // just a service +await AppCenterCrashes.setEnabled(false); // just a service +``` + +### Analytics + +#### Track events + +```dart +AppCenterAnalytics.trackEvent("map"); +AppCenterAnalytics.trackEvent("casino", { "dollars" : "10" }); // with custom properties +``` ## Getting Started -For help getting started with Flutter, view our online -[documentation](http://flutter.io/). - -For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). \ No newline at end of file +See the `example` directory for a complete sample app using Visual Studio App Center. \ No newline at end of file diff --git a/android/src/main/java/com/yourcompany/appcenter/AppcenterPlugin.java b/android/src/main/java/com/yourcompany/appcenter/AppcenterPlugin.java deleted file mode 100644 index ab80301..0000000 --- a/android/src/main/java/com/yourcompany/appcenter/AppcenterPlugin.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.yourcompany.appcenter; - -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodChannel.MethodCallHandler; -import io.flutter.plugin.common.MethodChannel.Result; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.PluginRegistry.Registrar; - -/** - * AppcenterPlugin - */ -public class AppcenterPlugin implements MethodCallHandler { - /** - * Plugin registration. - */ - public static void registerWith(Registrar registrar) { - final MethodChannel channel = new MethodChannel(registrar.messenger(), "appcenter"); - channel.setMethodCallHandler(new AppcenterPlugin()); - } - - @Override - public void onMethodCall(MethodCall call, Result result) { - if (call.method.equals("getPlatformVersion")) { - result.success("Android " + android.os.Build.VERSION.RELEASE); - } else { - result.notImplemented(); - } - } -} diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 0000000..90b5f65 --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,36 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +if ENV['FLUTTER_FRAMEWORK_DIR'] == nil + abort('Please set FLUTTER_FRAMEWORK_DIR to the directory containing Flutter.framework') +end + +target 'Runner' do + # Pods for Runner + + # Flutter Pods + pod 'Flutter', :path => ENV['FLUTTER_FRAMEWORK_DIR'] + + if File.exists? '../.flutter-plugins' + flutter_root = File.expand_path('..') + File.foreach('../.flutter-plugins') { |line| + plugin = line.split(pattern='=') + if plugin.length == 2 + name = plugin[0].strip() + path = plugin[1].strip() + resolved_path = File.expand_path("#{path}/ios", flutter_root) + pod name, :path => resolved_path + else + puts "Invalid plugin specification: #{line}" + end + } + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 0000000..1f04407 --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,46 @@ +PODS: + - appcenter (0.0.1): + - AppCenter + - Flutter + - AppCenter (1.0.1): + - AppCenter/Analytics (= 1.0.1) + - AppCenter/Crashes (= 1.0.1) + - AppCenter/Analytics (1.0.1): + - AppCenter/Core + - AppCenter/Core (1.0.1) + - AppCenter/Crashes (1.0.1): + - AppCenter/Core + - appcenter_analytics (0.0.1): + - AppCenter/Analytics + - Flutter + - appcenter_crashes (0.0.1): + - AppCenter/Crashes + - Flutter + - Flutter (1.0.0) + +DEPENDENCIES: + - appcenter (from `/Users/alois/flutter_plugin_appcenter/src/appcenter/ios`) + - appcenter_analytics (from `/Users/alois/flutter_plugin_appcenter/src/appcenter_analytics/ios`) + - appcenter_crashes (from `/Users/alois/flutter_plugin_appcenter/src/appcenter_crashes/ios`) + - Flutter (from `/Users/alois/flutter/bin/cache/artifacts/engine/ios`) + +EXTERNAL SOURCES: + appcenter: + :path: /Users/alois/flutter_plugin_appcenter/src/appcenter/ios + appcenter_analytics: + :path: /Users/alois/flutter_plugin_appcenter/src/appcenter_analytics/ios + appcenter_crashes: + :path: /Users/alois/flutter_plugin_appcenter/src/appcenter_crashes/ios + Flutter: + :path: /Users/alois/flutter/bin/cache/artifacts/engine/ios + +SPEC CHECKSUMS: + AppCenter: 1d9e08e4ffe7a8eab6e9741a12d27e44074e73a7 + appcenter: ec63d9079174977ead44a0040ff083d6dd4c94c5 + appcenter_analytics: 46cd35cb5fac57f7a4b2ae5d5040f984b4ad4b5a + appcenter_crashes: 1b06d86617183e4778779b59f85a25c4bbc89493 + Flutter: d674e78c937094a75ac71dd77e921e840bea3dbf + +PODFILE CHECKSUM: 351e02e34b831289961ec3558a535cbd2c4965d2 + +COCOAPODS: 1.3.1 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index ba49890..1e7c97f 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 513419C92C83CB08834F5354 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 54CE9D792210C22D5C6E8F8E /* libPods-Runner.a */; }; 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; @@ -43,6 +44,7 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 54CE9D792210C22D5C6E8F8E /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; @@ -65,12 +67,28 @@ files = ( 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + 513419C92C83CB08834F5354 /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 0AF805DA95AB24C0E846AF07 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 54CE9D792210C22D5C6E8F8E /* libPods-Runner.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 655B30EC1DAC555983B099AB /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -91,7 +109,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, + 655B30EC1DAC555983B099AB /* Pods */, + 0AF805DA95AB24C0E846AF07 /* Frameworks */, ); sourceTree = ""; }; @@ -134,12 +153,15 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 51044FEB4B5932DC48FE2B1F /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 96D9A8465C60EEE798E7F303 /* [CP] Embed Pods Frameworks */, + 18512D816A7A23D58E333AC8 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -200,6 +222,21 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 18512D816A7A23D58E333AC8 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -214,6 +251,42 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; }; + 51044FEB4B5932DC48FE2B1F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 96D9A8465C60EEE798E7F303 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${PODS_ROOT}/../../../../flutter/bin/cache/artifacts/engine/ios/Flutter.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/example/lib/main.dart b/example/lib/main.dart index f4cb8de..7396cea 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,6 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:appcenter/appcenter.dart'; +import 'package:appcenter_analytics/appcenter_analytics.dart'; +import 'package:appcenter_crashes/appcenter_crashes.dart'; +import 'package:flutter/foundation.dart' show defaultTargetPlatform; +import 'package:flutter/foundation.dart' show TargetPlatform; void main() => runApp(new MyApp()); @@ -10,7 +14,15 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - String _platformVersion = 'Unknown'; + + String _app_secret; + String _installId = 'Unknown'; + bool _areAnalyticsEnabled = false, _areCrashesEnabled = false; + + _MyAppState() { + final ios = defaultTargetPlatform == TargetPlatform.iOS; + _app_secret = ios ? "a8a33033-ef2f-4911-a664-a7d118287ce7" : "3f1f3b0e-24ff-436a-b42d-3c08b117d46a"; + } @override initState() { @@ -20,22 +32,20 @@ class _MyAppState extends State { // Platform messages are asynchronous, so we initialize in an async method. initPlatformState() async { - String platformVersion; - // Platform messages may fail, so we use a try/catch PlatformException. - try { - platformVersion = await Appcenter.platformVersion; - } on PlatformException { - platformVersion = 'Failed to get platform version.'; - } + await AppCenter.start(_app_secret, [AppCenterAnalytics.id, AppCenterCrashes.id]); - // If the widget was removed from the tree while the asynchronous platform - // message was in flight, we want to discard the reply rather than calling - // setState to update our non-existent appearance. if (!mounted) return; + var installId = await AppCenter.installId; + + var areAnalyticsEnabled = await AppCenterAnalytics.isEnabled; + var areCrashesEnabled = await AppCenterCrashes.isEnabled; + setState(() { - _platformVersion = platformVersion; + _installId = installId; + _areAnalyticsEnabled = areAnalyticsEnabled; + _areCrashesEnabled = areCrashesEnabled; }); } @@ -46,8 +56,28 @@ class _MyAppState extends State { appBar: new AppBar( title: new Text('Plugin example app'), ), - body: new Center( - child: new Text('Running on: $_platformVersion\n'), + body: new Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + new Text('Install identifier: $_installId'), + new Text('Analytics: $_areAnalyticsEnabled'), + new Text('Crashes: $_areCrashesEnabled'), + new Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + new Text('Send events'), + new IconButton( + icon: new Icon(Icons.map), + tooltip: 'map', + onPressed: () { AppcenterAnalytics.trackEvent("map"); }, + ), + new IconButton( + icon: new Icon(Icons.casino), + tooltip: 'casino', + onPressed: () { AppcenterAnalytics.trackEvent("casino", { "dollars" : "10" }); }, + ), + ]) + ] ), ), ); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 37a32dd..cf9e366 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -4,9 +4,6 @@ description: Demonstrates how to use the appcenter plugin. dependencies: flutter: sdk: flutter - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.0 dev_dependencies: @@ -14,46 +11,13 @@ dev_dependencies: sdk: flutter appcenter: - path: ../ + path: ../src/appcenter -# For information on the generic Dart part of this file, see the -# following page: https://www.dartlang.org/tools/pub/pubspec + appcenter_analytics: + path: ../src/appcenter_analytics + + appcenter_crashes: + path: ../src/appcenter_crashes -# The following section is specific to Flutter. flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.io/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.io/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.io/custom-fonts/#from-packages diff --git a/ios/Classes/AppcenterPlugin.m b/ios/Classes/AppcenterPlugin.m deleted file mode 100644 index afb8407..0000000 --- a/ios/Classes/AppcenterPlugin.m +++ /dev/null @@ -1,20 +0,0 @@ -#import "AppcenterPlugin.h" - -@implementation AppcenterPlugin -+ (void)registerWithRegistrar:(NSObject*)registrar { - FlutterMethodChannel* channel = [FlutterMethodChannel - methodChannelWithName:@"appcenter" - binaryMessenger:[registrar messenger]]; - AppcenterPlugin* instance = [[AppcenterPlugin alloc] init]; - [registrar addMethodCallDelegate:instance channel:channel]; -} - -- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { - if ([@"getPlatformVersion" isEqualToString:call.method]) { - result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]); - } else { - result(FlutterMethodNotImplemented); - } -} - -@end diff --git a/lib/appcenter.dart b/lib/appcenter.dart deleted file mode 100644 index 5b6aa0a..0000000 --- a/lib/appcenter.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/services.dart'; - -class Appcenter { - static const MethodChannel _channel = - const MethodChannel('appcenter'); - - static Future get platformVersion => - _channel.invokeMethod('getPlatformVersion'); -} diff --git a/pubspec.yaml b/pubspec.yaml deleted file mode 100644 index 5703c5d..0000000 --- a/pubspec.yaml +++ /dev/null @@ -1,49 +0,0 @@ -name: appcenter -description: A new flutter plugin project. -version: 0.0.1 -author: -homepage: - -dependencies: - flutter: - sdk: flutter - -# For information on the generic Dart part of this file, see the -# following page: https://www.dartlang.org/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - plugin: - androidPackage: com.yourcompany.appcenter - pluginClass: AppcenterPlugin - - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.io/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.io/assets-and-images/#resolution-aware. - - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.io/custom-fonts/#from-packages diff --git a/src/appcenter/CHANGELOG.md b/src/appcenter/CHANGELOG.md new file mode 100644 index 0000000..a3464b2 --- /dev/null +++ b/src/appcenter/CHANGELOG.md @@ -0,0 +1 @@ +## [0.0.1] - Initial release diff --git a/src/appcenter/LICENSE b/src/appcenter/LICENSE new file mode 100644 index 0000000..e8eaac4 --- /dev/null +++ b/src/appcenter/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Aloïs Deniel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/appcenter/README.md b/src/appcenter/README.md new file mode 100644 index 0000000..7621faa --- /dev/null +++ b/src/appcenter/README.md @@ -0,0 +1,59 @@ +# Visual Studio App Center Plugin for Flutter + +[![pub package](https://img.shields.io/pub/v/appcenter.svg)](https://pub.dartlang.org/packages/appcenter) + +Several Flutter plugins to use the [Microsoft Visual Studio App Center SDKs](https://docs.microsoft.com/en-us/appcenter/sdk/). + +*Note*: This plugin is still under development, and some APIs (*Distribute* and *Push* are still missing) might not be available yet. [Feedback](https://github.com/aloisdeniel/flutter_plugin_appcenter/issues) and [Pull Requests](https://github.com/aloisdeniel/flutter_plugin_appcenter/pulls) are most welcome! + +## Setup + +To use this plugin: + +1. Connect to [Visual Studio App Center Portal](https://appcenter.ms/apps) +1. From the index page, select `Add new` and create a new **iOS application (Platform: Objective-C/Swift)**, and keep your iOS app secret (ex: `123cfac9-123b-123a-123f-123273416a48`). +1. From the index page, select `Add new` and create a new **Android application (Platform: Java)**, and keep your Android app secret (ex: `321cfac9-123b-123a-123f-123273416a48`). +1. Add those as [dependencies in your pubspec.yaml file](https://flutter.io/platform-plugins/): + * `appcenter` + * `appcenter_analytics` + * `appcenter_crashes` + +## Usage + +### Global + +```dart +import 'package:appcenter/appcenter.dart'; +import 'package:appcenter_analytics/appcenter_analytics.dart'; +import 'package:appcenter_crashes/appcenter_crashes.dart'; +``` + +#### Starting services + +```dart +final ios = defaultTargetPlatform == TargetPlatform.iOS; +var app_secret = ios ? "123cfac9-123b-123a-123f-123273416a48" : "321cfac9-123b-123a-123f-123273416a48"; + +await AppCenter.start(app_secret, [AppCenterAnalytics.id, AppCenterCrashes.id]); +``` + +#### Enabling or disabling services + +```dart +await AppCenter.setEnabled(false); // global +await AppCenterAnalytics.setEnabled(false); // just a service +await AppCenterCrashes.setEnabled(false); // just a service +``` + +### Analytics + +#### Track events + +```dart +AppCenterAnalytics.trackEvent("map"); +AppCenterAnalytics.trackEvent("casino", { "dollars" : "10" }); // with custom properties +``` + +## Getting Started + +See the `example` directory for a complete sample app using Visual Studio App Center. \ No newline at end of file diff --git a/android/.gitignore b/src/appcenter/android/.gitignore similarity index 100% rename from android/.gitignore rename to src/appcenter/android/.gitignore diff --git a/android/build.gradle b/src/appcenter/android/build.gradle similarity index 80% rename from android/build.gradle rename to src/appcenter/android/build.gradle index 15a341a..eaed192 100644 --- a/android/build.gradle +++ b/src/appcenter/android/build.gradle @@ -1,4 +1,4 @@ -group 'com.yourcompany.appcenter' +group 'com.aloisdeniel.flutter.appcenter' version '1.0-SNAPSHOT' buildscript { @@ -39,4 +39,8 @@ android { lintOptions { disable 'InvalidPackage' } + dependencies { + def appCenterSdkVersion = '1.1.0' + compile "com.microsoft.appcenter:appcenter:${appCenterSdkVersion}" + } } diff --git a/android/gradle.properties b/src/appcenter/android/gradle.properties similarity index 100% rename from android/gradle.properties rename to src/appcenter/android/gradle.properties diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/src/appcenter/android/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from android/gradle/wrapper/gradle-wrapper.jar rename to src/appcenter/android/gradle/wrapper/gradle-wrapper.jar diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/src/appcenter/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from android/gradle/wrapper/gradle-wrapper.properties rename to src/appcenter/android/gradle/wrapper/gradle-wrapper.properties diff --git a/android/gradlew b/src/appcenter/android/gradlew similarity index 100% rename from android/gradlew rename to src/appcenter/android/gradlew diff --git a/android/gradlew.bat b/src/appcenter/android/gradlew.bat similarity index 100% rename from android/gradlew.bat rename to src/appcenter/android/gradlew.bat diff --git a/android/settings.gradle b/src/appcenter/android/settings.gradle similarity index 100% rename from android/settings.gradle rename to src/appcenter/android/settings.gradle diff --git a/android/src/main/AndroidManifest.xml b/src/appcenter/android/src/main/AndroidManifest.xml similarity index 100% rename from android/src/main/AndroidManifest.xml rename to src/appcenter/android/src/main/AndroidManifest.xml diff --git a/src/appcenter/android/src/main/java/com/aloisdeniel/flutter/appcenter/AppcenterPlugin.java b/src/appcenter/android/src/main/java/com/aloisdeniel/flutter/appcenter/AppcenterPlugin.java new file mode 100644 index 0000000..3d6fc39 --- /dev/null +++ b/src/appcenter/android/src/main/java/com/aloisdeniel/flutter/appcenter/AppcenterPlugin.java @@ -0,0 +1,101 @@ +package com.aloisdeniel.flutter.appcenter; + +import java.util.UUID; +import java.util.List; +import java.util.ArrayList; +import android.app.Application; + +import com.microsoft.appcenter.AppCenter; +import com.microsoft.appcenter.utils.async.AppCenterConsumer; + +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.PluginRegistry.Registrar; + +/** + * AppcenterPlugin + */ +public class AppcenterPlugin implements MethodCallHandler { + + private Registrar registrar; + + private AppcenterPlugin(Registrar registrar) { + this.registrar = registrar; + } + + /** + * Plugin registration. + */ + public static void registerWith(Registrar registrar) { + final MethodChannel channel = new MethodChannel(registrar.messenger(), "aloisdeniel.github.com/flutter_plugin_appcenter/appcenter"); + + final AppcenterPlugin plugin = new AppcenterPlugin(registrar); + channel.setMethodCallHandler(plugin); + } + + @Override + public void onMethodCall(MethodCall call, final Result result) { + + Application app = this.registrar.activity().getApplication(); + + switch (call.method) { + case "installId": + AppCenter.getInstallId().thenAccept(new AppCenterConsumer() { + @Override + public void accept(UUID uuid) { + result.success(uuid.toString()); + } + }); + + break; + case "isEnabled": + AppCenter.isEnabled().thenAccept(new AppCenterConsumer() { + @Override + public void accept(Boolean enabled) { + result.success(enabled.booleanValue()); + } + }); + + break; + case "setEnabled": + Boolean isEnabled = call.argument("isEnabled"); + AppCenter.setEnabled(isEnabled).thenAccept(new AppCenterConsumer() { + @Override + public void accept(Void v) { + result.success(null); + } + }); + break; + case "configure": + String secret = call.argument("app_secret"); + AppCenter.configure(app, secret); + result.success(null); + break; + case "start": + String start_secret = call.argument("app_secret"); + List services = call.argument("services"); + List servicesClasses = new ArrayList(); + for (String name : services) { + try { + Class c = Class.forName(name); + servicesClasses.add(c); + } + catch(ClassNotFoundException notFound) { + + } + } + + Class[] servicesClassesArray = new Class[servicesClasses.size()]; + servicesClassesArray = servicesClasses.toArray(servicesClassesArray); + AppCenter.start(app, start_secret, servicesClassesArray); + result.success(null); + break; + + default: + result.notImplemented(); + break; + } + } +} diff --git a/appcenter.iml b/src/appcenter/appcenter.iml similarity index 100% rename from appcenter.iml rename to src/appcenter/appcenter.iml diff --git a/appcenter_android.iml b/src/appcenter/appcenter_android.iml similarity index 100% rename from appcenter_android.iml rename to src/appcenter/appcenter_android.iml diff --git a/ios/.gitignore b/src/appcenter/ios/.gitignore similarity index 100% rename from ios/.gitignore rename to src/appcenter/ios/.gitignore diff --git a/ios/Assets/.gitkeep b/src/appcenter/ios/Assets/.gitkeep similarity index 100% rename from ios/Assets/.gitkeep rename to src/appcenter/ios/Assets/.gitkeep diff --git a/ios/Classes/AppcenterPlugin.h b/src/appcenter/ios/Classes/AppcenterPlugin.h similarity index 100% rename from ios/Classes/AppcenterPlugin.h rename to src/appcenter/ios/Classes/AppcenterPlugin.h diff --git a/src/appcenter/ios/Classes/AppcenterPlugin.m b/src/appcenter/ios/Classes/AppcenterPlugin.m new file mode 100644 index 0000000..eded5cd --- /dev/null +++ b/src/appcenter/ios/Classes/AppcenterPlugin.m @@ -0,0 +1,66 @@ +#import "AppcenterPlugin.h" + +#import + +@implementation AppcenterPlugin ++ (void)registerWithRegistrar:(NSObject*)registrar +{ + FlutterMethodChannel* channel = [FlutterMethodChannel + methodChannelWithName:@"aloisdeniel.github.com/flutter_plugin_appcenter/appcenter" + binaryMessenger:[registrar messenger]]; + AppcenterPlugin* instance = [[AppcenterPlugin alloc] init]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + +- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result +{ + if([@"installId" isEqualToString:call.method]) + { + result([[MSAppCenter installId] UUIDString]); + } + else if([@"isEnabled" isEqualToString:call.method]) + { + result([NSNumber numberWithBool:[MSAppCenter isEnabled]]); + } + else if([@"setEnabled" isEqualToString:call.method]) + { + // Arguments + NSNumber *isEnabled = call.arguments[@"isEnabled"]; + + // Invoking plugin method + [MSAppCenter setEnabled:isEnabled.boolValue]; + result(nil); + + } + else if([@"configure" isEqualToString:call.method]) + { + // Arguments + NSString *secret = call.arguments[@"app_secret"]; + + // Invoking plugin method + [MSAppCenter configureWithAppSecret:secret]; + result(nil); + } + else if([@"start" isEqualToString:call.method]) + { + // Arguments + NSString *secret = call.arguments[@"app_secret"]; + NSArray *services = call.arguments[@"services"]; + + // Processing arguments + NSMutableArray *serviceClasses = [[NSMutableArray alloc]init]; + for (NSString* name in services) { + [serviceClasses addObject: NSClassFromString(name)]; + } + + // Invoking plugin method + [MSAppCenter start:secret withServices:serviceClasses]; + result(nil); + } + else + { + result(FlutterMethodNotImplemented); + } +} + +@end diff --git a/ios/appcenter.podspec b/src/appcenter/ios/appcenter.podspec similarity index 75% rename from ios/appcenter.podspec rename to src/appcenter/ios/appcenter.podspec index 3537d25..f25da43 100644 --- a/ios/appcenter.podspec +++ b/src/appcenter/ios/appcenter.podspec @@ -8,13 +8,14 @@ Pod::Spec.new do |s| s.description = <<-DESC A new flutter plugin project. DESC - s.homepage = 'http://example.com' + s.homepage = 'http://github.com/aloisdeniel/flutter_plugin_appcenter' s.license = { :file => '../LICENSE' } - s.author = { 'Your Company' => 'email@example.com' } + s.author = { 'Aloïs Deniel' => 'alois.deniel@outlook.com' } s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.public_header_files = 'Classes/**/*.h' s.dependency 'Flutter' + s.dependency 'AppCenter' s.ios.deployment_target = '8.0' end diff --git a/src/appcenter/lib/appcenter.dart b/src/appcenter/lib/appcenter.dart new file mode 100644 index 0000000..ec84631 --- /dev/null +++ b/src/appcenter/lib/appcenter.dart @@ -0,0 +1,27 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; + +class AppCenter { + + static const MethodChannel _channel = const MethodChannel('aloisdeniel.github.com/flutter_plugin_appcenter/appcenter'); + + /// Starts App Center services + static Future configure(String app_secret) => _channel.invokeMethod('configure', { + 'app_secret': app_secret, + }); + + static Future start(String app_secret, List services) => _channel.invokeMethod('start', { + 'app_secret': app_secret, + 'services': services + }); + + static Future get installId => _channel.invokeMethod('installId'); + + static Future get isEnabled => _channel.invokeMethod('isEnabled'); + + static Future setEnabled(bool isEnabled) => _channel.invokeMethod('setEnabled', { + 'isEnabled': isEnabled, + }); +} + diff --git a/src/appcenter/pubspec.yaml b/src/appcenter/pubspec.yaml new file mode 100644 index 0000000..7f8614f --- /dev/null +++ b/src/appcenter/pubspec.yaml @@ -0,0 +1,12 @@ +name: appcenter +description: Visual Studio App Center plugin for Flutter applications. +version: 0.0.1 +author: Aloïs Deniel +homepage: https://github.com/aloisdeniel/flutter_plugin_appcenter +dependencies: + flutter: + sdk: flutter +flutter: + plugin: + androidPackage: com.aloisdeniel.flutter.appcenter + pluginClass: AppcenterPlugin \ No newline at end of file diff --git a/src/appcenter_analytics/.gitignore b/src/appcenter_analytics/.gitignore new file mode 100644 index 0000000..14c7d4c --- /dev/null +++ b/src/appcenter_analytics/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock diff --git a/src/appcenter_analytics/CHANGELOG.md b/src/appcenter_analytics/CHANGELOG.md new file mode 100644 index 0000000..a3464b2 --- /dev/null +++ b/src/appcenter_analytics/CHANGELOG.md @@ -0,0 +1 @@ +## [0.0.1] - Initial release diff --git a/src/appcenter_analytics/LICENSE b/src/appcenter_analytics/LICENSE new file mode 100644 index 0000000..e8eaac4 --- /dev/null +++ b/src/appcenter_analytics/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Aloïs Deniel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/appcenter_analytics/README.md b/src/appcenter_analytics/README.md new file mode 100644 index 0000000..60492f0 --- /dev/null +++ b/src/appcenter_analytics/README.md @@ -0,0 +1,56 @@ +# Visual Studio App Center (Analytics) Plugin for Flutter + +[![pub package](https://img.shields.io/pub/v/appcenter.svg)](https://pub.dartlang.org/packages/appcenter) + +Several Flutter plugins to use the [Microsoft Visual Studio App Center SDKs](https://docs.microsoft.com/en-us/appcenter/sdk/). + +*Note*: This plugin is still under development, and some APIs (*Distribute* and *Push* are still missing) might not be available yet. [Feedback](https://github.com/aloisdeniel/flutter_plugin_appcenter/issues) and [Pull Requests](https://github.com/aloisdeniel/flutter_plugin_appcenter/pulls) are most welcome! + +## Setup + +To use this plugin: + +1. Connect to [Visual Studio App Center Portal](https://appcenter.ms/apps) +1. From the index page, select `Add new` and create a new **iOS application (Platform: Objective-C/Swift)**, and keep your iOS app secret (ex: `123cfac9-123b-123a-123f-123273416a48`). +1. From the index page, select `Add new` and create a new **Android application (Platform: Java)**, and keep your Android app secret (ex: `321cfac9-123b-123a-123f-123273416a48`). +1. Add those as [dependencies in your pubspec.yaml file](https://flutter.io/platform-plugins/): + * `appcenter` + * `appcenter_analytics` + +## Usage + +### Global + +```dart +import 'package:appcenter/appcenter.dart'; +import 'package:appcenter_analytics/appcenter_analytics.dart'; +``` + +#### Starting services + +```dart +final ios = defaultTargetPlatform == TargetPlatform.iOS; +var app_secret = ios ? "123cfac9-123b-123a-123f-123273416a48" : "321cfac9-123b-123a-123f-123273416a48"; + +await AppCenter.start(app_secret, [AppCenterAnalytics.id]); +``` + +#### Enabling or disabling services + +```dart +await AppCenter.setEnabled(false); // global +await AppCenterAnalytics.setEnabled(false); // just a service +``` + +### Analytics + +#### Track events + +```dart +AppCenterAnalytics.trackEvent("map"); +AppCenterAnalytics.trackEvent("casino", { "dollars" : "10" }); // with custom properties +``` + +## Getting Started + +See the `example` directory for a complete sample app using Visual Studio App Center. \ No newline at end of file diff --git a/src/appcenter_analytics/android/.gitignore b/src/appcenter_analytics/android/.gitignore new file mode 100644 index 0000000..c6cbe56 --- /dev/null +++ b/src/appcenter_analytics/android/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/src/appcenter_analytics/android/build.gradle b/src/appcenter_analytics/android/build.gradle new file mode 100644 index 0000000..aeb5900 --- /dev/null +++ b/src/appcenter_analytics/android/build.gradle @@ -0,0 +1,46 @@ +group 'com.aloisdeniel.flutter.appcenter_analytics' +version '1.0-SNAPSHOT' + +buildscript { + repositories { + jcenter() + maven { + url "https://maven.google.com" + } + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.3.3' + } +} + +rootProject.allprojects { + repositories { + jcenter() + maven { + url "https://maven.google.com" + } + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.3' + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + lintOptions { + disable 'InvalidPackage' + } + dependencies { + def appCenterSdkVersion = '1.1.0' + compile "com.microsoft.appcenter:appcenter-analytics:${appCenterSdkVersion}" + } +} diff --git a/src/appcenter_analytics/android/gradle.properties b/src/appcenter_analytics/android/gradle.properties new file mode 100644 index 0000000..8bd86f6 --- /dev/null +++ b/src/appcenter_analytics/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/src/appcenter_analytics/android/gradle/wrapper/gradle-wrapper.jar b/src/appcenter_analytics/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..13372ae Binary files /dev/null and b/src/appcenter_analytics/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/src/appcenter_analytics/android/gradle/wrapper/gradle-wrapper.properties b/src/appcenter_analytics/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..45e7f14 --- /dev/null +++ b/src/appcenter_analytics/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/src/appcenter_analytics/android/gradlew b/src/appcenter_analytics/android/gradlew new file mode 100755 index 0000000..9d82f78 --- /dev/null +++ b/src/appcenter_analytics/android/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/src/appcenter_analytics/android/gradlew.bat b/src/appcenter_analytics/android/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/src/appcenter_analytics/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/appcenter_analytics/android/settings.gradle b/src/appcenter_analytics/android/settings.gradle new file mode 100644 index 0000000..0df7e18 --- /dev/null +++ b/src/appcenter_analytics/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'appcenter_analytics' diff --git a/src/appcenter_analytics/android/src/main/AndroidManifest.xml b/src/appcenter_analytics/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..5ad6c33 --- /dev/null +++ b/src/appcenter_analytics/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/src/appcenter_analytics/android/src/main/java/com/aloisdeniel/flutter/appcenter_analytics/AppcenterAnalyticsPlugin.java b/src/appcenter_analytics/android/src/main/java/com/aloisdeniel/flutter/appcenter_analytics/AppcenterAnalyticsPlugin.java new file mode 100644 index 0000000..062a2de --- /dev/null +++ b/src/appcenter_analytics/android/src/main/java/com/aloisdeniel/flutter/appcenter_analytics/AppcenterAnalyticsPlugin.java @@ -0,0 +1,68 @@ +package com.aloisdeniel.flutter.appcenter_analytics; + +import java.util.UUID; +import java.util.Map; +import android.app.Application; + +import com.microsoft.appcenter.analytics.Analytics; +import com.microsoft.appcenter.utils.async.AppCenterConsumer; + +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.PluginRegistry.Registrar; + +/** + * AppcenterAnalyticsPlugin + */ +public class AppcenterAnalyticsPlugin implements MethodCallHandler { + private Registrar registrar; + + private AppcenterAnalyticsPlugin(Registrar registrar) { + this.registrar = registrar; + } + + /** + * Plugin registration. + */ + public static void registerWith(Registrar registrar) { + final MethodChannel channel = new MethodChannel(registrar.messenger(), "aloisdeniel.github.com/flutter_plugin_appcenter/appcenter_analytics"); + + final AppcenterAnalyticsPlugin plugin = new AppcenterAnalyticsPlugin(registrar); + channel.setMethodCallHandler(plugin); + } + + @Override + public void onMethodCall(MethodCall call, final Result result) { + + switch (call.method) { + case "isEnabled": + Analytics.isEnabled().thenAccept(new AppCenterConsumer() { + @Override + public void accept(Boolean enabled) { + result.success(enabled.booleanValue()); + } + }); + + break; + case "setEnabled": + Boolean isEnabled = call.argument("isEnabled"); + Analytics.setEnabled(isEnabled).thenAccept(new AppCenterConsumer() { + @Override + public void accept(Void v) { + result.success(null); + } + }); + break; + case "trackEvent": + String name = call.argument("name"); + Map properties = call.argument("properties"); + Analytics.trackEvent(name, properties); + break; + default: + result.notImplemented(); + break; + } + } +} diff --git a/src/appcenter_analytics/appcenter_analytics.iml b/src/appcenter_analytics/appcenter_analytics.iml new file mode 100644 index 0000000..5522468 --- /dev/null +++ b/src/appcenter_analytics/appcenter_analytics.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/appcenter_analytics/appcenter_analytics_android.iml b/src/appcenter_analytics/appcenter_analytics_android.iml new file mode 100644 index 0000000..0ebb6c9 --- /dev/null +++ b/src/appcenter_analytics/appcenter_analytics_android.iml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/appcenter_analytics/ios/.gitignore b/src/appcenter_analytics/ios/.gitignore new file mode 100644 index 0000000..956c87f --- /dev/null +++ b/src/appcenter_analytics/ios/.gitignore @@ -0,0 +1,31 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + diff --git a/src/appcenter_analytics/ios/Assets/.gitkeep b/src/appcenter_analytics/ios/Assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/appcenter_analytics/ios/Classes/AppcenterAnalyticsPlugin.h b/src/appcenter_analytics/ios/Classes/AppcenterAnalyticsPlugin.h new file mode 100644 index 0000000..3c24ad6 --- /dev/null +++ b/src/appcenter_analytics/ios/Classes/AppcenterAnalyticsPlugin.h @@ -0,0 +1,4 @@ +#import + +@interface AppcenterAnalyticsPlugin : NSObject +@end diff --git a/src/appcenter_analytics/ios/Classes/AppcenterAnalyticsPlugin.m b/src/appcenter_analytics/ios/Classes/AppcenterAnalyticsPlugin.m new file mode 100644 index 0000000..606976f --- /dev/null +++ b/src/appcenter_analytics/ios/Classes/AppcenterAnalyticsPlugin.m @@ -0,0 +1,55 @@ +#import "AppCenterAnalyticsPlugin.h" + +#import + +@implementation AppcenterAnalyticsPlugin + ++ (void)registerWithRegistrar:(NSObject*)registrar +{ + FlutterMethodChannel* channel = [FlutterMethodChannel + methodChannelWithName:@"aloisdeniel.github.com/flutter_plugin_appcenter/appcenter_analytics" + binaryMessenger:[registrar messenger]]; + AppcenterAnalyticsPlugin* instance = [[AppcenterAnalyticsPlugin alloc] init]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + +- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result +{ + if([@"isEnabled" isEqualToString:call.method]) + { + result([NSNumber numberWithBool:[MSAnalytics isEnabled]]); + } + else if([@"setEnabled" isEqualToString:call.method]) + { + // Arguments + NSNumber *isEnabled = call.arguments[@"isEnabled"]; + + // Invoking plugin method + [MSAnalytics setEnabled:isEnabled.boolValue]; + result(nil); + } + else if([@"trackEvent" isEqualToString:call.method]) + { + // Arguments + NSString *name = call.arguments[@"name"]; + NSDictionary *properties = call.arguments[@"properties"]; + + // Invoking plugin method + + if([properties count] == 0) + { + [MSAnalytics trackEvent:name]; + } + else + { + [MSAnalytics trackEvent:name withProperties:properties]; + } + result(nil); + } + else + { + result(FlutterMethodNotImplemented); + } +} + +@end diff --git a/src/appcenter_analytics/ios/appcenter_analytics.podspec b/src/appcenter_analytics/ios/appcenter_analytics.podspec new file mode 100644 index 0000000..8ca93eb --- /dev/null +++ b/src/appcenter_analytics/ios/appcenter_analytics.podspec @@ -0,0 +1,22 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'appcenter_analytics' + s.version = '0.0.1' + s.summary = 'A new flutter plugin project.' + s.description = <<-DESC +A new flutter plugin project. + DESC + s.homepage = 'http://github.com/aloisdeniel/flutter_plugin_appcenter' + s.license = { :file => '../LICENSE' } + s.author = { 'Aloïs Deniel' => 'alois.deniel@outlook.com' } + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.public_header_files = 'Classes/**/*.h' + s.dependency 'Flutter' + s.dependency 'AppCenter/Analytics' + + s.ios.deployment_target = '8.0' +end + diff --git a/src/appcenter_analytics/lib/appcenter_analytics.dart b/src/appcenter_analytics/lib/appcenter_analytics.dart new file mode 100644 index 0000000..768c911 --- /dev/null +++ b/src/appcenter_analytics/lib/appcenter_analytics.dart @@ -0,0 +1,23 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:flutter/foundation.dart' show defaultTargetPlatform; +import 'package:flutter/foundation.dart' show TargetPlatform; + +class AppCenterAnalytics { + + static String get id => (defaultTargetPlatform == TargetPlatform.iOS) ? "MSAnalytics" : "com.microsoft.appcenter.analytics.Analytics"; + + static const MethodChannel _channel = const MethodChannel('aloisdeniel.github.com/flutter_plugin_appcenter/appcenter_analytics'); + + static Future get isEnabled => _channel.invokeMethod('isEnabled'); + + static Future setEnabled(bool isEnabled) => _channel.invokeMethod('setEnabled', { + 'isEnabled': isEnabled, + }); + + static Future trackEvent(String name, [Map properties]) => _channel.invokeMethod('trackEvent', { + 'name': name, + 'properties' : properties ?? {}, + }); +} diff --git a/src/appcenter_analytics/pubspec.yaml b/src/appcenter_analytics/pubspec.yaml new file mode 100644 index 0000000..fb3ac11 --- /dev/null +++ b/src/appcenter_analytics/pubspec.yaml @@ -0,0 +1,14 @@ +name: appcenter_analytics +description: Visual Studio App Center (Analytics) plugin for Flutter applications. +version: 0.0.1 +author: Aloïs Deniel +homepage: https://github.com/aloisdeniel/flutter_plugin_appcenter + +dependencies: + flutter: + sdk: flutter + +flutter: + plugin: + androidPackage: com.aloisdeniel.flutter.appcenter_analytics + pluginClass: AppcenterAnalyticsPlugin \ No newline at end of file diff --git a/src/appcenter_crashes/.gitignore b/src/appcenter_crashes/.gitignore new file mode 100644 index 0000000..14c7d4c --- /dev/null +++ b/src/appcenter_crashes/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock diff --git a/src/appcenter_crashes/CHANGELOG.md b/src/appcenter_crashes/CHANGELOG.md new file mode 100644 index 0000000..a3464b2 --- /dev/null +++ b/src/appcenter_crashes/CHANGELOG.md @@ -0,0 +1 @@ +## [0.0.1] - Initial release diff --git a/src/appcenter_crashes/LICENSE b/src/appcenter_crashes/LICENSE new file mode 100644 index 0000000..f847d07 --- /dev/null +++ b/src/appcenter_crashes/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Aloïs Deniel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/appcenter_crashes/README.md b/src/appcenter_crashes/README.md new file mode 100644 index 0000000..dae7c24 --- /dev/null +++ b/src/appcenter_crashes/README.md @@ -0,0 +1,46 @@ +# Visual Studio App Center (Crash) Plugin for Flutter + +[![pub package](https://img.shields.io/pub/v/appcenter.svg)](https://pub.dartlang.org/packages/appcenter) + +Several Flutter plugins to use the [Microsoft Visual Studio App Center SDKs](https://docs.microsoft.com/en-us/appcenter/sdk/). + +*Note*: This plugin is still under development, and some APIs (*Distribute* and *Push* are still missing) might not be available yet. [Feedback](https://github.com/aloisdeniel/flutter_plugin_appcenter/issues) and [Pull Requests](https://github.com/aloisdeniel/flutter_plugin_appcenter/pulls) are most welcome! + +## Setup + +To use this plugin: + +1. Connect to [Visual Studio App Center Portal](https://appcenter.ms/apps) +1. From the index page, select `Add new` and create a new **iOS application (Platform: Objective-C/Swift)**, and keep your iOS app secret (ex: `123cfac9-123b-123a-123f-123273416a48`). +1. From the index page, select `Add new` and create a new **Android application (Platform: Java)**, and keep your Android app secret (ex: `321cfac9-123b-123a-123f-123273416a48`). +1. Add those as [dependencies in your pubspec.yaml file](https://flutter.io/platform-plugins/): + * `appcenter` + * `appcenter_crashes` + +## Usage + +### Global + +```dart +import 'package:appcenter/appcenter.dart'; +import 'package:appcenter_crashes/appcenter_crashes.dart'; +``` + +#### Starting service + +```dart +final ios = defaultTargetPlatform == TargetPlatform.iOS; +var app_secret = ios ? "123cfac9-123b-123a-123f-123273416a48" : "321cfac9-123b-123a-123f-123273416a48"; + +await AppCenter.start(app_secret, [AppCenterCrashes.id]); +``` + +#### Enabling or disabling service + +```dart +await AppCenterCrashes.setEnabled(false); // just a service +``` + +## Getting Started + +See the `example` directory for a complete sample app using Visual Studio App Center. \ No newline at end of file diff --git a/src/appcenter_crashes/android/.gitignore b/src/appcenter_crashes/android/.gitignore new file mode 100644 index 0000000..c6cbe56 --- /dev/null +++ b/src/appcenter_crashes/android/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/src/appcenter_crashes/android/build.gradle b/src/appcenter_crashes/android/build.gradle new file mode 100644 index 0000000..f3a84ce --- /dev/null +++ b/src/appcenter_crashes/android/build.gradle @@ -0,0 +1,46 @@ +group 'com.yourcompany.appcentercrashes' +version '1.0-SNAPSHOT' + +buildscript { + repositories { + jcenter() + maven { + url "https://maven.google.com" + } + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.3.3' + } +} + +rootProject.allprojects { + repositories { + jcenter() + maven { + url "https://maven.google.com" + } + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.3' + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + lintOptions { + disable 'InvalidPackage' + } + dependencies { + def appCenterSdkVersion = '1.1.0' + compile "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}" + } +} diff --git a/src/appcenter_crashes/android/gradle.properties b/src/appcenter_crashes/android/gradle.properties new file mode 100644 index 0000000..8bd86f6 --- /dev/null +++ b/src/appcenter_crashes/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/src/appcenter_crashes/android/gradle/wrapper/gradle-wrapper.jar b/src/appcenter_crashes/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..13372ae Binary files /dev/null and b/src/appcenter_crashes/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/src/appcenter_crashes/android/gradle/wrapper/gradle-wrapper.properties b/src/appcenter_crashes/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..45e7f14 --- /dev/null +++ b/src/appcenter_crashes/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/src/appcenter_crashes/android/gradlew b/src/appcenter_crashes/android/gradlew new file mode 100755 index 0000000..9d82f78 --- /dev/null +++ b/src/appcenter_crashes/android/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/src/appcenter_crashes/android/gradlew.bat b/src/appcenter_crashes/android/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/src/appcenter_crashes/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/appcenter_crashes/android/settings.gradle b/src/appcenter_crashes/android/settings.gradle new file mode 100644 index 0000000..112c14b --- /dev/null +++ b/src/appcenter_crashes/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'appcenter_crashes' diff --git a/src/appcenter_crashes/android/src/main/AndroidManifest.xml b/src/appcenter_crashes/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6be58be --- /dev/null +++ b/src/appcenter_crashes/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/src/appcenter_crashes/android/src/main/java/com/aloisdeniel/flutter/appcenter_crashes/AppcenterCrashesPlugin.java b/src/appcenter_crashes/android/src/main/java/com/aloisdeniel/flutter/appcenter_crashes/AppcenterCrashesPlugin.java new file mode 100644 index 0000000..6547a1d --- /dev/null +++ b/src/appcenter_crashes/android/src/main/java/com/aloisdeniel/flutter/appcenter_crashes/AppcenterCrashesPlugin.java @@ -0,0 +1,62 @@ +package com.aloisdeniel.flutter.appcenter_crashes; + +import java.util.UUID; +import android.app.Application; + +import com.microsoft.appcenter.crashes.Crashes; +import com.microsoft.appcenter.utils.async.AppCenterConsumer; + +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.PluginRegistry.Registrar; + +/** + * AppcenterCrashesPlugin + */ +public class AppcenterCrashesPlugin implements MethodCallHandler { + private Registrar registrar; + + private AppcenterCrashesPlugin(Registrar registrar) { + this.registrar = registrar; + } + + /** + * Plugin registration. + */ + public static void registerWith(Registrar registrar) { + final MethodChannel channel = new MethodChannel(registrar.messenger(), "aloisdeniel.github.com/flutter_plugin_appcenter/appcenter_crashes"); + + final AppcenterCrashesPlugin plugin = new AppcenterCrashesPlugin(registrar); + channel.setMethodCallHandler(plugin); + } + + @Override + public void onMethodCall(MethodCall call, final Result result) { + + switch (call.method) { + case "isEnabled": + Crashes.isEnabled().thenAccept(new AppCenterConsumer() { + @Override + public void accept(Boolean enabled) { + result.success(enabled.booleanValue()); + } + }); + + break; + case "setEnabled": + Boolean isEnabled = call.argument("isEnabled"); + Crashes.setEnabled(isEnabled).thenAccept(new AppCenterConsumer() { + @Override + public void accept(Void v) { + result.success(null); + } + }); + break; + default: + result.notImplemented(); + break; + } + } +} diff --git a/src/appcenter_crashes/appcenter_crashes.iml b/src/appcenter_crashes/appcenter_crashes.iml new file mode 100644 index 0000000..5522468 --- /dev/null +++ b/src/appcenter_crashes/appcenter_crashes.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/appcenter_crashes/appcenter_crashes_android.iml b/src/appcenter_crashes/appcenter_crashes_android.iml new file mode 100644 index 0000000..0ebb6c9 --- /dev/null +++ b/src/appcenter_crashes/appcenter_crashes_android.iml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/appcenter_crashes/ios/.gitignore b/src/appcenter_crashes/ios/.gitignore new file mode 100644 index 0000000..956c87f --- /dev/null +++ b/src/appcenter_crashes/ios/.gitignore @@ -0,0 +1,31 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + diff --git a/src/appcenter_crashes/ios/Assets/.gitkeep b/src/appcenter_crashes/ios/Assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/appcenter_crashes/ios/Classes/AppcenterCrashesPlugin.h b/src/appcenter_crashes/ios/Classes/AppcenterCrashesPlugin.h new file mode 100644 index 0000000..38558b3 --- /dev/null +++ b/src/appcenter_crashes/ios/Classes/AppcenterCrashesPlugin.h @@ -0,0 +1,4 @@ +#import + +@interface AppcenterCrashesPlugin : NSObject +@end diff --git a/src/appcenter_crashes/ios/Classes/AppcenterCrashesPlugin.m b/src/appcenter_crashes/ios/Classes/AppcenterCrashesPlugin.m new file mode 100644 index 0000000..4dd3960 --- /dev/null +++ b/src/appcenter_crashes/ios/Classes/AppcenterCrashesPlugin.m @@ -0,0 +1,37 @@ +#import "AppcenterCrashesPlugin.h" + +#import + +@implementation AppcenterCrashesPlugin + ++ (void)registerWithRegistrar:(NSObject*)registrar +{ + FlutterMethodChannel* channel = [FlutterMethodChannel + methodChannelWithName:@"aloisdeniel.github.com/flutter_plugin_appcenter/appcenter_crashes" + binaryMessenger:[registrar messenger]]; + AppcenterCrashesPlugin* instance = [[AppcenterCrashesPlugin alloc] init]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + +- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result +{ + if([@"isEnabled" isEqualToString:call.method]) + { + result([NSNumber numberWithBool:[MSCrashes isEnabled]]); + } + else if([@"setEnabled" isEqualToString:call.method]) + { + // Arguments + NSNumber *isEnabled = call.arguments[@"isEnabled"]; + + // Invoking plugin method + [MSCrashes setEnabled:isEnabled.boolValue]; + result(nil); + } + else + { + result(FlutterMethodNotImplemented); + } +} + +@end diff --git a/src/appcenter_crashes/ios/appcenter_crashes.podspec b/src/appcenter_crashes/ios/appcenter_crashes.podspec new file mode 100644 index 0000000..ad0812a --- /dev/null +++ b/src/appcenter_crashes/ios/appcenter_crashes.podspec @@ -0,0 +1,22 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'appcenter_crashes' + s.version = '0.0.1' + s.summary = 'A new flutter plugin project.' + s.description = <<-DESC +A new flutter plugin project. + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.public_header_files = 'Classes/**/*.h' + s.dependency 'Flutter' + s.dependency 'AppCenter/Crashes' + + s.ios.deployment_target = '8.0' +end + diff --git a/src/appcenter_crashes/lib/appcenter_crashes.dart b/src/appcenter_crashes/lib/appcenter_crashes.dart new file mode 100644 index 0000000..ad87bca --- /dev/null +++ b/src/appcenter_crashes/lib/appcenter_crashes.dart @@ -0,0 +1,18 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:flutter/foundation.dart' show defaultTargetPlatform; +import 'package:flutter/foundation.dart' show TargetPlatform; + +class AppCenterCrashes { + + static String get id => (defaultTargetPlatform == TargetPlatform.iOS) ? "MSCrashes" : "com.microsoft.appcenter.crashes.Crashes"; + + static const MethodChannel _channel = const MethodChannel('aloisdeniel.github.com/flutter_plugin_appcenter/appcenter_crashes'); + + static Future get isEnabled => _channel.invokeMethod('isEnabled'); + + static Future setEnabled(bool isEnabled) => _channel.invokeMethod('setEnabled', { + 'isEnabled': isEnabled, + }); +} diff --git a/src/appcenter_crashes/pubspec.yaml b/src/appcenter_crashes/pubspec.yaml new file mode 100644 index 0000000..95479c6 --- /dev/null +++ b/src/appcenter_crashes/pubspec.yaml @@ -0,0 +1,14 @@ +name: appcenter_crashes +description: Visual Studio App Center (Crashes) plugin for Flutter applications. +version: 0.0.1 +author: Aloïs Deniel +homepage: https://github.com/aloisdeniel/flutter_plugin_appcenter + +dependencies: + flutter: + sdk: flutter + +flutter: + plugin: + androidPackage: com.aloisdeniel.flutter.appcenter_crashes + pluginClass: AppcenterCrashesPlugin