Packages
mob_new
0.1.0
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.45
0.1.44
0.1.43
0.1.42
0.1.40
0.1.33
0.1.30
0.1.29
0.1.28
0.1.27
0.1.26
0.1.25
0.1.24
0.1.23
0.1.21
0.1.20
0.1.19
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Project generator for the Mob mobile framework
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/mob.new.ex
defmodule Mix.Tasks.Mob.New do
use Mix.Task
@shortdoc "Create a new Mob mobile app project"
@moduledoc """
Creates a new Mob project with Android and iOS boilerplate.
mix mob.new APP_NAME [--no-install] [--dest DIR]
## Options
* `--no-install` — skip running `mix deps.get` after generation
* `--dest DIR` — create project in DIR (default: current directory)
## What gets generated
APP_NAME/
mix.exs
lib/APP_NAME/app.ex
lib/APP_NAME/hello_screen.ex
android/
settings.gradle
build.gradle
app/
build.gradle
src/main/
AndroidManifest.xml
java/com/mob/APP_NAME/MainActivity.java
ios/
beam_main.m
Info.plist
After generation, run:
cd APP_NAME
mix mob.install # icon generation + any first-run setup
"""
@switches [no_install: :boolean, dest: :string]
@impl Mix.Task
def run(argv) do
{opts, args, _} = OptionParser.parse(argv, strict: @switches)
app_name =
case args do
[name | _] -> name
[] -> Mix.raise("Usage: mix mob.new APP_NAME")
end
unless valid_app_name?(app_name) do
Mix.raise("App name must be lowercase letters, digits, and underscores only (e.g. my_app).")
end
dest_dir = opts[:dest] || "."
project_dir = Path.join(dest_dir, app_name)
Mix.shell().info([:green, "* creating ", :reset, project_dir])
case MobNew.ProjectGenerator.generate(app_name, dest_dir) do
{:error, reason} ->
Mix.raise(reason)
{:ok, project_dir} ->
print_created_files(project_dir, app_name)
unless opts[:no_install] do
fetch_deps(project_dir)
end
print_next_steps(app_name, opts[:no_install])
end
end
# ── private ──────────────────────────────────────────────────────────────────
defp fetch_deps(project_dir) do
Mix.shell().info("")
Mix.shell().info("Fetching dependencies...")
case Mix.shell().cmd("mix deps.get", cd: project_dir) do
0 -> :ok
_ -> Mix.shell().info([:yellow, "* deps.get failed — run it manually inside #{project_dir}", :reset])
end
end
defp print_created_files(project_dir, app_name) do
files = [
"mix.exs",
"lib/#{app_name}/app.ex",
"lib/#{app_name}/hello_screen.ex",
"android/settings.gradle",
"android/build.gradle",
"android/app/build.gradle",
"android/app/src/main/AndroidManifest.xml",
"android/app/src/main/java/com/mob/#{app_name}/MainActivity.java",
"ios/beam_main.m",
"ios/Info.plist"
]
Enum.each(files, fn f ->
Mix.shell().info([:green, "* creating ", :reset, Path.join(project_dir, f)])
end)
end
defp print_next_steps(app_name, no_install) do
install_hint =
if no_install,
do: "\n mix deps.get",
else: ""
Mix.shell().info("""
Your Mob app #{app_name} is ready!
#{install_hint}
cd #{app_name}
mix mob.install # generates app icon + first-run setup
Then to run on a device:
mix mob.deploy # build + push BEAMs + launch
mix mob.watch # auto-push changes while developing
""")
end
defp valid_app_name?(name), do: Regex.match?(~r/^[a-z][a-z0-9_]*$/, name)
end